ゲームループでの独立したレンダリングの更新のポイントは何ですか?


74

ゲームループに関する記事、書籍、ディスカッションは多数あります。しかし、私はかなり頻繁にこのようなものに出くわします:

while(running)
{
    processInput();
    while(isTimeForUpdate)
    {
        update();
    }
    render();
}

このアプローチについて基本的に私を悩ませているのは、「更新に依存しない」レンダリングです。たとえば、まったく変更がないときにフレームをレンダリングします。だから私の質問は、なぜこのアプローチが頻繁に教えられているのですか?



12
レンダリングのすべての変更がゲームの状態に反映されるわけではありません。そして、そのコードの要点を誤解しているのではないかと思います-更新ごとに複数回レンダリングするのではなく、レンダリングごとに複数回更新することができます。
ルアーン

13
コードwhile (isTimeForUpdate)ではなく、読み取りますことに注意してくださいif (isTimeForUpdate)。主な目標は、がなかったrender()ときではなく、の間update()update()繰り返し存在することrender()です。とにかく、両方の状況に有効な用途があります。前者はupdate、現在の時間などの暗黙的な状態に基づいてレンダリングされるものを変更するなど、状態が関数の外部で変更できる場合に有効です。後者は、物理エンジンが多くの小さくて正確な更新を行う可能性を与えるため、有効です。たとえば、障害物を「ゆがむ」可能性を減らします。
ティエリー

より論理的な質問は、「
更新

1
何もしないアップデートはどれくらいの頻度でありますか?バックグラウンドアニメーションや画面上の時計も更新していませんか?
pjc50

回答:


113

私たちがこの共通の大会にたどり着くまでの長い歴史があり、その途中で多くの魅力的な挑戦があります。それで、私はそれを段階的に動機付けようとします:

1.問題:デバイスが異なる速度で実行される

最新のPCで古いDOSゲームをプレイしようとすると、プレイできないほど高速に実行されます。

多くの古いゲームには非常に単純な更新ループがありました。入力を収集し、ゲームの状態を更新し、経過時間を考慮せずにハードウェアが許す限り高速にレンダリングしていました。つまり、ハードウェアが変更されるとすぐに、ゲームプレイが変更されます。

一般に、昨年の携帯電話でも最新モデルでも、最高級のゲームデスクトップでも、さまざまなデバイスで一貫した体験とゲーム感覚をプレーヤーに持たせたいと思っています中間層のラップトップ。

特に、競争力のあるゲーム(マルチプレイヤーまたはリーダーボード経由)では、特定のデバイスで実行しているプレイヤーが他のデバイスよりも有利になるのは望ましくありません。

ここで確実な解決策は、ゲームプレイ状態の更新のレートをロックすることです。これにより、結果が常に同じになることを保証できます。

2.では、フレームレートをロックするだけで(例:VSyncを使用)、ゲームプレイ状態の更新とレンダリングをロックステップで実行するのはなぜですか?

これは機能しますが、視聴者にとって必ずしも満足できるものではありません。安定した30 fpsでの実行がゲームのゴールドスタンダードと見なされていたのは長い間ありました。現在、特にマルチプレイヤーアクションゲームでは、プレーヤーは通常60 fpsを最小バーとして期待しています。また、一部の古いタイトルは、期待が変わったため著しく途切れて見えるようになりました。また、特にフレームレートロックに反対するPCプレーヤーのボーカルグループもいます。彼らは最先端のハードウェアに多額の費用を支払い、そのコンピューティングマッスルを使用して、可能な限りスムーズで最高の忠実度のレンダリングを実現したいと考えています。

特にVRでは、フレームレートが重要であり、標準は忍び寄っています。最近のVRの復活の初期には、ゲームは約60 fpsで実行されていました。90がより標準になり、PSVRのようなハーウェアが120をサポートし始めています。これはまだ増え続けています。そのため、VRゲームのフレームレートが現在実行可能なものに制限されている場合、ハードウェアと期待がさらに発展するにつれて取り残される可能性があります。

(原則として、「プレイヤーはXXXよりも速いものを知覚できない」と言われるときは、フレームを順番に認識するような特定のタイプの「知覚」に基づいているため、注意が必要です。敏感です。)

ここでの最後の問題は、ロックされたフレームレートを使用するゲームも保守的である必要があるということです-異常に多くのオブジェクトを更新および表示しているゲームの瞬間にヒットした場合、フレームを見逃したくない締め切りと顕著なスタッターまたはヒッチを引き起こします。したがって、ヘッドルームを確保するためにコンテンツの予算を十分に低く設定するか、最小スペックのハードウェアで最悪のパフォーマンスにプレイエクスペリエンス全体を縛り付けないように、より複雑な動的品質調整機能に投資する必要があります。

これは、パフォーマンスの問題が開発の後半に現れ、既存のすべてのシステムが構築され、ロックステップレンダリングフレームレートが今では常にヒットできないと仮定した場合に特に問題になる可能性があります。更新レートとレンダリングレートを分離すると、パフォーマンスの変動に柔軟に対応できます。

3.一定のタイムステップで更新しても、(2)と同じ問題が発生しませんか?

これは元の質問の核心だと思います:更新を分離し、ゲームの状態の更新を間にせずに2つのフレームをレンダリングする場合、目に見える変化がないため、低いフレームレートでのロックステップレンダリングと同じではありませんスクリーン?

実際には、ゲームがこれらの更新のデカップリングを有効に使用するいくつかの異なる方法があります。

a)更新レートはレンダリングされたフレームレートより速くなる可能性があります

tyjkennが別の答えで指摘しているように、特に物理学はレンダリングよりも高い周波数でステップされることが多く、これは統合エラーを最小限に抑え、より正確な衝突を与えるのに役立ちます。したがって、レンダリングされたフレーム間で0または1の更新を行うのではなく、5または10または50を使用できます。

現在、120 fpsでレンダリングしているプレーヤーはフレームごとに2つの更新を取得できますが、30 fpsで低スペックのハードウェアレンダリングを実行しているプレーヤーはフレームごとに8つの更新を取得し、両方のゲームは同じ秒あたりの同じゲームプレイ速度で実行されます。優れたハードウェアは見た目を滑らかにしますが、ゲームプレイの動作を根本的に変えることはありません。

ここで、更新レートがフレームレートと一致しない場合、2つの間に「ビート周波数」を取得できるというリスクがあります。例えば。ほとんどのフレームには4つのゲーム状態の更新と少しの残りのための十分な時間があります。その後、フレーム内で5つの更新を行うのに十分な時間を節約して、動きを少しジャンプまたはスタッターします。これは...によって対処することができます

b)更新間のゲーム状態の補間(または外挿)

ここでは、しばしばゲームの状態を1つの固定タイムステップで将来的に維持し、最新の2つの状態からの十分な情報を保存して、それらの間の任意のポイントをレンダリングできます。次に、画面に新しいフレームを表示する準備ができたら、表示目的のみに適切な瞬間にブレンドします(つまり、ここで基礎となるゲームプレイ状態を変更しません)

完了したら、右これは、動きがスムーズにバターを感じさせる、とさえ私たちはドロップしない限り、フレームレートでのいくつかの変動をマスクすることができますあまりにも低いです。

c)ゲームプレイ状態以外の変更に滑らかさを追加する

ゲームプレイの状態を補間しなくても、スムーズな勝利を得ることができます。

キャラクターアニメーション、パーティクルシステムまたはVFX、HUDなどのユーザーインターフェイス要素などの純粋に視覚的な変更は、多くの場合、ゲームプレイ状態の固定タイムステップとは別に更新されます。これは、フレームごとにゲームプレイの状態を複数回チェックしている場合、すべてのチェックでコストを支払うのではなく、最終レンダーパスでのみ支払うことを意味します。代わりに、これらのエフェクトの再生速度をフレームの長さに合わせてスケーリングするため、(1)で説明したように、ゲームの速度や公平性に影響を与えることなく、レンダリングフレームレートが許容する限りスムーズに再生します。

カメラの動きもこれを行うことができます- 特にVRでは、同じフレームを複数回表示することがありますが、その間プレイヤーの頭の動きを考慮して再投影するため、知覚できるレイテンシと快適性を改善できますすべてを高速でネイティブにレンダリングしないでください。一部のゲームストリーミングシステム(ゲームはサーバー上で実行され、プレーヤーはシンクライアントのみを実行します)もこのバージョンを使用します。

4.なぜすべてにその(c)スタイルを使用しないのですか?アニメーションとUIで機能する場合、ゲームプレイ状態の更新を現在のフレームレートに合わせて単純にスケーリングすることはできませんか?

はい*これは可能ですが、簡単ではありません。

この答えはすでに少し長いので、すべての面倒な詳細については説明しません。簡単な要約です。

  • 線形変化のdeltaTime可変長更新に調整するための作品 による乗算(例:一定速度での移動、タイマーのカウントダウン、またはアニメーションタイムラインに沿った進行)

  • 残念ながら、ゲームの多くの側面は非線形です。重力のような単純なものでも、さまざまなフレームレートで結果が発散しないように、より高度な統合技術または高解像度のサブステップが必要です。プレーヤーの入力と制御自体が非線形性の大きな原因です。

  • 特に、離散衝突の検出と解決の結果は更新レートに依存し、フレームが長くなりすぎるとトンネリングとジッターのエラーが発生します。したがって、可変フレームレートにより、より多くのコンテンツに対してより複雑で高価な連続衝突検出方法を使用するか、物理学の変動を許容する必要があります。連続的な衝突検出でさえ、オブジェクトが弧を描いて移動する場合、より短い時間ステップを必要とする課題に直面します...

したがって、中程度の複雑さのゲームの一般的なケースでは、deltaTimeスケーリングによって完全に一貫した動作と公平性を維持することは、非常に困難でメンテナンス集約型から完全に実行不可能な状態です。

更新レートを標準化すると、多くの場合より単純なコードで、さまざまな条件でより一貫した動作を保証できます。

更新レートをレンダリングから切り離すことで、ゲームプレイロジックを変更せずに、エクスペリエンスのスムーズさとパフォーマンスを柔軟に制御できます

それでも真に「完璧な」フレームレートの独立性は得られませんが、ゲームの非常に多くのアプローチと同様に、特定のゲームのニーズに「十分に」応える制御可能な方法を提供します。それが一般的に有用な出発点として教えられている理由です。


2
すべてが同じフレームレートを使用する場合、すべてを同期すると、コントローラーがサンプリングされてからゲームの状態が反応するまでの遅延を最小限に抑えることができます。一部の古いマシンでの多くのゲームでは、最悪の場合の時間は17ミリ秒未満です(コントロールは垂直ブランクの開始時に読み取られ、ゲーム状態の変更が適用され、ビームが画面を下に移動している間に次のフレームがレンダリングされます) 。多くの場合、デカップリングにより、最悪の場合の時間は大幅に増加します。
-supercat

3
より複雑な更新パイプラインにより、意図せずに遅延が発生しやすくなるのは事実ですが、正しく実装された場合の分離アプローチの必要な結果ではありません。実際、レイテンシーを削減することさえできるかもしれません。60 fpsでレンダリングするゲームを見てみましょう。ロックステップread-update-renderでは、最悪の場合のレイテンシは17ミリ秒です(現時点ではグラフィックパイプラインとディスプレイレイテンシを無視します)。(read-update)x(n>1)-render同じフレームレートの分離ループでは、最悪の場合のレイテンシは同じかそれ以上になります。これは、入力を頻繁にチェックして処理するためです。:)
DMGregory

3
リアルタイムの経過を考慮していない古いゲームに関する興味深いサイドノートでは、元のスペースインベーダーのアーケードにはレンダリング力による不具合があり、プレイヤーが敵の船を破壊し、レンダリング、したがってゲームの更新がスピードアップし、誤って、ゲームの象徴的な難易度曲線。
オスクロ

1
@DMGregory:物事が非同期に行われた場合、ゲームループがコントロールをポーリングした直後にコントロールの変更が発生し、現在のものの後のゲームイベントサイクルがレンダリングループがゲームの状態を取得した直後に終了する可能性があり、ビデオ出力システムが現在のフレームバッファーを取得した直後に現在のループの後のレンダリングループが終了するため、最悪の場合の時間は、2つのゲームループ時間と2つのレンダリング時間と2つのフレーム期間だけで済みます。物事を適切に同期すると、半分になります。
-supercat

1
@オスクロ:それはグリッチではありませんでした。更新ループの速度は、画面上にある侵略者の数に関係なく一定ですが、ゲームはすべての更新ループですべての侵略者を描画するわけではありません。
-supercat

8

他の答えは良いですし、ゲームループが存在し、レンダリングループから分離する必要がある理由について説明します。ただし、「変更がなかったときにフレームをレンダリングする理由」の特定の例については。それは本当にハードウェアと複雑さに帰着します。

ビデオカードはステートマシンであり、同じことを何度も繰り返すのが得意です。変更されたものだけをレンダリングする場合、実際にはそれ以上ではなく高価です。ほとんどのシナリオでは、静的なものはほとんどありません。FPSゲームで少し左に移動すると、画面上のものの98%のピクセルデータが変更され、フレーム全体をレンダリングすることもできます。

しかし、主に、複雑さ。更新中に変更されたすべてを追跡することは、すべてをやり直すか、アルゴリズムの古い結果を追跡し、新しい結果と比較し、変更が異なる場合のみそのピクセルをレンダリングする必要があるため、はるかに高価です。システムに依存します。

ハードウェアなどの設計は、現在の規約に合わせて大幅に最適化されており、ステートマシンは最初から良いモデルでした。


5
ここでは、何かが変更された場合にのみレンダリング(すべて)(質問が尋ねる内容)と、変更された部分のみをレンダリング(回答が説明する内容)に区別する必要があります。
DMGregory

それは事実であり、私は最初の段落と2番目の段落を区別しようとしました。フレームがまったく変わらないことはめったにないので、総合的な答えと一緒にこの見方をすることが重要だと思いました。
ワドル

これに加えて、レンダリングしない理由はないことに注意してください。あなたは常にあなたの通話すべてのフレームを(あなたがしたいのレンダリングのための時間を持っていることを知って、より良い、この場合はするので、特に! -あなたは常にあなたの通話すべてのフレームをレンダリングするための時間を持っていることを知っている)ので、非常に少ない害が「不要」を行う際にありますレンダリング基本的には実際には出てきません。
スティーブンスタドニッキー

@StevenStadnicki すべてのフレームをすべてレンダリングするのに大きな時間コストがかからないことは事実です(多くの状態が一度に変更されるたびにそれを行うには予算内の時間が必要だからです)。しかし、ラップトップ、タブレット、電話、またはポータブルゲームシステムなどのポータブルデバイスの場合、プレーヤーのバッテリーを効率的に使用するために、冗長なレンダリングを避けることを考慮する必要があります。これは主に、画面の大部分がプレイヤーのアクション間でフレームを変更しないUIが重いゲームに適用され、ゲームのアーキテクチャによっては実装が常に実用的ではない場合があります。
DMGregory

6

レンダリングは通常、ゲームループの中で最も遅いプロセスです。人間は60を超えるフレームレートの違いに簡単に気付かないため、それよりも速くレンダリングに時間を費やすことはそれほど重要ではありません。ただし、より速い速度からより多くの恩恵を受ける他のプロセスがあります。物理学は一つです。1つのループでの変更が大きすぎると、オブジェクトが壁を越えてグリッチを起こす可能性があります。大きな増分で単純な衝突エラーを回避する方法があるかもしれませんが、多くの複雑な物理的相互作用では、同じ精度を得ることができません。ただし、物理ループがより頻繁に実行される場合は、オブジェクトが毎回レンダリングされることなく小さな増分で移動できるため、グリッチの可能性が低くなります。より多くのリソースが繊細な物理エンジンに向けられ、ユーザーが見ることができないより多くのフレームを描くことに無駄が減ります。

これは、グラフィックを多用するゲームでは特に重要です。ゲームループごとに1つのレンダーがあり、プレイヤーが最も強力なマシンを持っていなかった場合、ゲーム内でfpsが30または40に低下するポイントが存在する可能性があります。グリッチを回避するために各物理変化を適度に小さくしようとすると、ゲームはかなり遅くなり始めます。プレイヤーは、自分のキャラクターが通常の速度の半分しか歩かないことに悩まされます。ただし、レンダリングレートがループの残りの部分から独立している場合、フレームレートが低下しても、プレーヤーは一定の歩行速度にとどまることができます。


1
または、たとえば、ティック間の時間を測定し、その時間にキャラクターがどれだけ進むべきかを計算しますか?固定されたスプライトアニメーションの時代は昔です!
グラハム

2
人間は一時的なエイリアシングがなければ60fpsより速く物を知覚することはできませんが、モーションブラーがない場合にスムーズなモーションを実現するために必要なフレームレートはそれよりもはるかに高い場合があります。一定の速度を超えると、回転しているホイールはブラーとして表示されますが、ソフトウェアがモーションブラーを適用せず、フレームごとにスポークの半分以上ホイールが回転すると、フレームレートが1000fpsであってもホイールの外観が悪くなる場合があります。
スーパーキャット

1
@Graham、それから物理学などの事柄がティックごとの大きな変化で誤動作する最初の段落から問題に遭遇します。フレームレートが十分に低下した場合、大きな変更を補正すると、プレーヤーが壁を完全に抜けてしまい、ヒットボックスが完全に失われる可能性があります。
tyjkenn

1
人間は通常60 fpsよりも速く知覚できないため、それよりも速くレンダリングするためにリソースを無駄にすることは無意味です。私はその声明に問題を取ります。VR HMDは90Hzでレンダリングされ、上昇しています。ヘッドセットで90Hzと60Hzの違いをはっきりと認識できると言ったら、私を信じてください。また、最近、CPUにバインドされたゲームがGPUにバインドされたゲームと同じくらい多く見られました。「レンダリングが通常最も遅いプロセスである」と言うことは必ずしも真実ではありません。
3Dave

@DavidLively、つまり「無意味」は誇張しすぎていたかもしれません。私が意図したのは、レンダリングがボトルネックになる傾向があり、ほとんどのゲームが60 fpsで問題なく見えることです。確かに、VRなどのいくつかの種類のゲームで重要な効果は、より速いフレームレートでしか得られませんが、それらは通常ではなく例外のように見えます。低速のマシンでゲームを実行している場合は、ほとんど目立たない高速フレームレートよりも、物理学の方がはるかに役立ちます。
tyjkenn

4

レンダリングサブシステムに「最後のレンダリングからの経過時間」という概念がある場合、質問のような構造は意味があります。

たとえば、ゲーム世界でのオブジェクトの位置が(x,y,z)、現在の移動ベクトルを追加で保存するアプローチで固定座標を介して表されるアプローチを考え(dx,dy,dz)ます。これで、メソッド内で位置の変更が発生するようにゲームループを記述できますupdateが、の間に移動の変更が発生するように設計することもできますupdate。後者のアプローチでは、ゲームの状態は実際には次まで変化しませんがupdaterender-より高い頻度で呼び出される関数は、わずかに更新された位置でオブジェクトを既に描画する可能性があります。これにより、技術的には表示内容と内部で表示される内容との間に相違が生じますが、その違いはほとんどの実用的な側面に関係なく、アニメーションをより滑らかに見せることができます。

たとえば、ネットワーク入力のレイテンシを考慮に入れる場合、ゲームの状態の「未来」を予測することは(間違っているリスクがあるにもかかわらず)良いアイデアです。


4

他の答えに加えて...

状態の変化を確認するには、かなりの処理が必要です。実際に処理を行う場合と比較して、変更を確認するのに同様の(またはそれ以上の)処理時間がかかる場合、状況は改善されていません。@Waddlesが言うように、画像をレンダリングする場合、ビデオカードは同じ愚かなことを何度も繰り返し行うの得意であり、単にデータを転送するよりもデータの各チャンクをチェックする方がコストがかかります処理のためにビデオカードに。また、レンダリングがゲームプレイである場合、最後のティックで画面が変更されないことはほとんどありません

また、レンダリングにはかなりのプロセッサ時間がかかると想定しています。これは、プロセッサとグラフィックカードに大きく依存します。何年もの間、より洗練されたレンダリング作業をグラフィックカードに徐々にオフロードし、プロセッサから必要なレンダリング入力を減らすことに焦点が当てられてきました。理想的には、プロセッサのrender()呼び出しでDMA転送を設定するだけで、それで終わりです。グラフィックカードへのデータの取得はメモリコントローラーに委任され、画像の生成はグラフィックカードに委任されます。プロセッサが並行して動作している間に、自分の時間でそれを行うことができます物理学、ゲームプレイエンジン、およびプロセッサがより優れている他のすべてのものを引き継ぎます。明らかに現実はそれよりもはるかに複雑ですが、システムの他の部分に作業をオフロードできることも重要な要素です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.