ウェブアニメーションのフレームレートFPSを計算する方法

ウェブアニメーションのフレームレートFPSを計算する方法

スムーズなアニメーションの基準

まず、いくつかの概念を明確にしましょう。 FPS は 1 秒あたりの画面更新回数を意味します。私たちが普段目にする連続画像は、一連の静止画像で構成されています。各画像はフレームと呼ばれます。FPS は、「フレーム」が変化する速度を表す物理量です。

理論的には、FPS が高いほど、アニメーションはスムーズになります。現在、ほとんどのデバイスの画面リフレッシュ レートは 1 秒あたり 60 回であるため、一般的に、アニメーション効果は FPS が 60 フレーム/秒、つまり各フレームに 16.67 ミリ秒かかるときに最適になります。

もちろん、FPSゲームをよくプレイする友人は、PUBG/CSGOな​​どのFPSゲームでは144Hzのリフレッシュレートのモニターの使用が推奨されていることを知っているはずです。144Hzモニターとは、具体的には1秒あたり144Hzのリフレッシュレートのモニターを指します。通常のモニターの60秒のリフレッシュレートと比較すると、画像の表示がよりスムーズになります。したがって、144Hz モニターは、視野角が高速移動を維持することが多い一人称シューティング ゲームに適しています。

ただし、これはディスプレイが提供する高リフレッシュ レート機能にすぎません。Web アニメーションの場合、サポートされるかどうかはブラウザーによって異なり、ほとんどのブラウザーのリフレッシュ レートは 1 秒あたり 60 回です。

直感的な感覚、さまざまなフレームレートの体験:

  • フレームレートが 50 ~ 60 FPS のアニメーションは非常にスムーズで快適です。
  • フレーム レートが 30 ~ 50 FPS のアニメーションの場合、感度レベルが異なるため、快適さのレベルは人によって異なります。
  • フレームレートが 30 FPS 未満のアニメーションでは、明らかな遅延と不快感を感じます。
  • フレームレートの変動が大きいアニメーションも、遅延を感じさせる原因になります。

さて、ページアニメーションの現在の FPS 値を正確に取得するにはどうすればよいでしょうか?

方法1: Chromeデベロッパーツールを使用する

Chrome は開発者向けに強力な機能を提供します。開発者ツールでは、次のように FPS メーター オプションを選択できます。

このボタンを使用すると、ページのフレーム レートのリアルタイム監視とページの GPU 使用率をオンにすることができます。

欠点:

  • 一度に1ページまたは数ページしか観察できず、手動でリアルタイム観察する必要がある。
  • データは主観的なものに過ぎず、継続的に報告または収集される非常に正確なデータは存在しません。

したがって、より賢明なアプローチが必要です。

方法 2: フレームタイミング API を使用する

次の方法を紹介する前に、基本的な知識を広めていきましょう。

Blinkカーネルの初期アーキテクチャ

Chrome ブラウザ カーネルの Blink レンダリング ページを例に挙げます。初期の Chrome ブラウザでは、各ページ タブは、メイン スレッドと合成スレッドを含む独立したレンダラー プロセスに対応しています。初期の Chrome カーネル アーキテクチャ:

その中で、メインスレッドは主に以下の処理を担当します。

  • Javascriptの計算と実行
  • CSSスタイルの計算
  • レイアウト計算
  • ページ要素をビットマップに描画する(ペイント)、つまりラスタライズする(ラスター)
  • ビットマップを合成スレッドに渡す

構成スレッドは主に次のことを行います。

  • ビットマップ(GraphicsLayerレイヤー)をテクスチャとしてGPUにアップロードする
  • ページの表示されている部分とすぐに表示される部分を計算する(スクロール)
  • CSSアニメーション
  • GPUにビットマップを画面に描画するように指示する

よし、霧さん、これは何ですか?実際、これら 2 つのスレッドを理解した後の次の概念は、CSS アニメーションと JS アニメーション (もちろん、どちらも Web アニメーションです) の微妙な違いを明確にすることです。

JSアニメーションとCSSアニメーションの微妙な違い

JS アニメーションの場合、実行されるフレーム レートは、メイン スレッドと合成スレッドの合計で消費される時間になります。スムーズなアニメーションを実現するには、各フレームの所要時間が 16.67 ミリ秒未満になるようにします。

CSSアニメーションについては、その処理はメインスレッドの影響を受けないため、合成スレッドの消費時間を取得することが期待されます。合成スレッドの描画頻度は、スクロールとCSSアニメーションの処理も反映します。

上記から導き出される主な結論は次のとおりです。メインスレッドと合成スレッドの各フレームにかかる時間がわかれば、対応する Web アニメーションのフレーム レートを大まかに把握できます。では、上記のフレームタイミング API はこの時点を取得するのに役立ちますか?

フレームタイミング API とは何ですか?

Frame Timing API は、Web Performance Timing API 標準のメンバーです。

Web パフォーマンス タイミング API は、開発者が Web サイトのさまざまな側面のパフォーマンスを正確に分析および制御し、Web サイトのパフォーマンスを向上させるために W3C によって開始されたパフォーマンス API 標準のセットです。

次のように、さまざまな機能を実行するための多くのサブクラス API が含まれています (パフォーマンス API を使用して Web フロントエンドのパフォーマンスを迅速に分析するから抜粋。もちろん、オリジナルの英語の紹介文「Web Performance Timing API」も読むことができます)。

どうやって使うの?ナビゲーション タイミング、パフォーマンス タイムライン、リソース タイミングを例にとると、互換性のあるブラウザーでは、これらは window.performance にマウントされた読み取り専用プロパティとして公開されます。

デバッガー コンソールに window.performance を出力し、タイミング プロパティを確認します。

このオブジェクト内の一連の変数は何を表しているのでしょうか? これらは、ページの読み込みプロセス全体におけるすべての重要な時点を表しています。次の図を詳しく見てみましょう。

この図と上記の window.performance.timing を使用すると、ページの各重要なノードで消費された時間を簡単にカウントできます。これが Web Performance Timing API の威力です。興味があれば、詳細を調べてページ統計に使用することができます。

フレームタイミング API の概要

さて、ようやく本題に戻りましょう。Web Performance Timing API の Frame Timing API を使用すると、各フレームのメイン スレッドと合成スレッドの時間を簡単に取得できます。または、各フレームにかかる時間を直接取得する方が簡単です。

レンダリング メイン スレッドと合成スレッドのレコードを取得します。各レコードに含まれる情報は、コードに示されているように、基本的に次のようになります (「開発者からのフィードバックが必要: フレーム タイミング API」を参照)。

var rendererEvents = window.performance.getEntriesByType("レンダラー");
var 複合スレッドイベント = window.performance.getEntriesByType("複合");

または:

var observer = new PerformanceObserver(function(list) {
    var perfEntries = list.getEntries();
    (var i = 0; i < perfEntries.length; i++) {
        console.log("フレーム: ", perfEntries[i]);
    }
});
 
// フレームタイミングをサブスクライブする
オブザーバー.observe({entryTypes: ['frame']});

各レコードには次の基本情報が含まれています。

{
  ソースフレーム番号: 120,
  開始時間: 1342.549374253
  CPU時間: 6.454313323
}

各レコードには、一意のフレーム番号、フレーム開始時刻、および cpuTime が含まれます。各レコードの startTime を計算することで、2 つのフレーム間の間隔を計算し、アニメーションのフレーム レートが 60 FPS に達するかどうかを判断できます。

しかし! Web Performance Timing API の全体的な互換性を見てみましょう。

Frame Timing API は良いのですが、現時点では互換性があまり良くありません。では、どの程度悪いのでしょうか?まだブラウザのサポートはなく、実験段階であり、将来志向のプログラミングです。私をからかってるの?こんなに長く話しても全然無駄だ…

方法3: requestAnimationFrame APIを使用する

Frame Timing API の説明に多くの時間を費やしましたが、最終的には互換性の問題によりまったく使用できなくなりました。しかし、これはこのような長い説明が役に立たないという意味ではありません。上記の紹介から、各フレームで固定の時点を取得できれば、その 2 つを減算することで 1 つのフレームで消費される時間を概算できることがわかっています。

そこで、別のアプローチを試してみましょう。今回は互換性の良いrequestAnimationFrame APIを使用します。

// 構文 window.requestAnimationFrame(callback);

requestAnimationFrame については、誰もがよく知っているはずです。このメソッドは、アニメーションを実行することをブラウザに伝え、次の再描画の前に、指定された関数を呼び出してアニメーションを更新するようにブラウザに要求します。

画面を更新する準備ができたら、このメソッドを適用します。これには、次のブラウザの再描画の前にアニメーション関数を実行することが必要になります。コールバックの回数は通常 1 秒あたり 60 回で、ほとんどのブラウザは通常 W3C が推奨するリフレッシュ レートと一致します。

requestAnimationFrame を使用して FPS を計算する原理

原則として、通常、requestAnimationFrame メソッドは 1 秒間に 60 回実行され、フレームがドロップされることはありません。アニメーションが時間 A に始まり、時間 B に終了し、x ミリ秒かかるとします。 requestAnimationFrame は合計で n 回実行されるため、このアニメーションのフレーム レートはおおよそ n / (B - A) になります。

コア コードは次のとおりです。これにより、1 秒あたりのページ フレーム レートを概算で計算できます。さらに、各アニメーションのフレーム レートを計算するために使用される rAF の実行回数を記録する allFrameCount も記録します。

var rAF = 関数(){
    戻る (
        ウィンドウのアニメーションフレームをリクエストします。
        window.webkitRequestAnimationFrame ||
        関数(コールバック){
            window.setTimeout(コールバック、1000 / 60);
        }
    );
}();
  
var フレーム = 0;
var allFrameCount = 0;
var lastTime = Date.now();
var lastFameTime = Date.now();
  
var loop = 関数() {
    var now = Date.now();
    var fs = (現在 - lastFameTime);
    var fps = Math.round(1000 / fs);
  
    lastFameTime = 現在;
    // 0 に設定しないでください。アニメーションの開始時と終了時のこの値の差を記録して FPS を計算します。
    すべてのフレーム数++;
    フレーム++;
  
    if (現在 > 1000 + 前回の時刻) {
        var fps = Math.round((frame * 1000) / (now - lastTime));
        console.log(`${new Date()} 1秒以内のFPS:`, fps);
        フレーム = 0;
        前回の時刻 = 現在;
    };
  
    rAF(ループ);
}
 
ループ();

テストのためにアニメーションが継続的に実行されているページを見つけると、コードが次のように実行されることがわかります。

ここでは、以前作成したページを使用してテストしました。Chromeを使用して、同時にページのFPSメーターを呼び出し、両方のリアルタイムFPS値を比較しました。基本的に一致しています。

テストページ、太陽系。上記のコードをこのページのコンソールに貼り付けて、データをテストできます。

右上隅のフレーム レートを比較すると、フレーム レートは基本的に同じです。ほとんどの場合、この方法は Web アニメーションのフレーム レートを適切に推定します。

特定のアニメーション プロセスのフレーム レートをカウントする必要がある場合は、アニメーションの開始時と終了時の allFrameCount の値を記録し、それを途中で消費された時間で割って、特定のアニメーション プロセスの FPS 値を取得するだけです。

この方法で計算された結果と実際のフレーム レートの間には、明らかに食い違いがあることに注意する必要があります。これは、前述のように、メイン スレッドと合成スレッドによって消費された時間を 1 フレームと見なすのではなく、JavaScript の 2 つのメイン スレッド実行間の時間間隔を 1 フレームと見なすためです。しかし、現段階では、それは受け入れられる方法です。

上記は、WebアニメーションのFPSを計算する方法の詳細です。WebアニメーションのFPSの計算の詳細については、123WORDPRESS.COMの他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • python-opencvを使用してビデオを読み取り、ビデオフレームの合計数とFPSを計算します。
  • Unity3DはOnGUIに基づいてFPSをリアルタイムで表示します
  • Unity OnGUIはゲームのFPSをリアルタイムで表示します
  • Pythonはビデオを読み取り、処理し、フレームレートfpsをリアルタイムで計算します。
  • Android で 1 秒あたりのフレーム数 (FPS) を測定する方法
  • Vueはカルーセルのフレームレート再生を実装します

<<:  Mysql の一般的なベンチマーク コマンドの概要

>>:  LinuxでHomebrewを使用する正しい方法

推薦する

Linux centos7 に phpMyAdmin をインストールするチュートリアル

yum install httpd php mariadb-server –yランプの動作環境を設定...

CentOS7 に ElasticSearch 6.4.1 をインストールするための詳細なチュートリアル

1. ElasticSearch 6.4.1 インストール パッケージを次の場所からダウンロードしま...

HTML+SassはHambergurMenu(ハンバーガーメニュー)を実装します

先日、外国人の方がHTML+CSSを使ってHamburgerMenuを実装している動画を見ました。最...

Vueプラグインの実装で発生した問題の概要

目次シーン紹介プラグインの実装問題1: 重複したヘッダーコンポーネント質問2: 別の実装アイデア質問...

MySQL の不正な文字列値の解決方法

MySQL を使用して中国語の文字を挿入すると、多くの友人から次のエラーが報告されます。 これは、文...

Dockerイメージのインポートとエクスポートの実装

GitLabのDocker使用法gitlab ドッカー起動コマンド docker run -d -p...

CSS でハニカム/六角形アトラスを実装するためのサンプルコード

理由は分かりませんが、UIではハニカム効果(手を広げたような効果)のデザインが好まれます。 1. 六...

jQueryをベースにカルーセル効果を実現する

この記事では、カルーセルマップの効果を実現するためのjQueryの具体的なコードを参考までに共有しま...

MySQL 接続失敗の一般的な障害と原因

==================================================...

jsドラッグ効果の原理と実装

ドラッグ機能は主に、ドラッグによる並べ替え、ポップアップ ボックスのドラッグと移動など、ユーザーがカ...

MySQL 5.7.23 解凍バージョンのインストールチュートリアル(画像とテキスト付き)

毎回インストールチュートリアルを探すのは面倒なので、後で確認できるように手順をバックアップします。解...

CentOS 7 で PHP 5.4 を 5.6 にアップグレードする方法の簡単な分析

1.ターミナルに入ったらPHPのバージョンを確認するphp -v出力は次のようになります。 PHP ...

WeChatアプレット開発によりホームページポップアップボックスアクティビティガイダンス機能が実現

目次1. 需要2. データベース設計3.Javaバックグラウンド構成の実装4. WeChatアプレッ...

LinuxシステムにおけるMySQLの一般的な操作コマンド

仕える: # chkconfig --list すべてのシステムサービスを一覧表示する# chkco...

デザイン理論: テキストの読みやすさと可読性

<br />少し前に、ビジネス上の必要性から、ラップトップに Souba をインストール...