Physics & constraints

Fixed Timestep / Substepping

固定タイムステップ

決まった刻みで物理更新を進める。

4 / 10

Interactive demo

Preparing the demo…

Fixed Timestep / Substepping

Drag to orbit, Ctrl/⌘ + scroll to zoom. Use two fingers on touch screens.

This explanation is currently available in Japanese.

ひとことで

描画のフレームレートに関係なく、物理の計算をいつも同じ時間刻み(例えば 1/60 秒)で進める方法です。描画 1 回の間にたまった時間を、決まった刻みで何回分か消化し、余った時間は次に持ち越します。そのうえで、直前 2 回の物理の結果を補間して描くと、結果は安定したまま、どんなフレームレートでもなめらかに見えます。

ゲームでの使いどころ

  • ジャンプの高さや飛距離をそろえる:フレームレートによってジャンプの高さが変わると、60 fps の人は届くのに 30 fps の人は届かない足場ができてしまいます。
  • リプレイと対戦:同じ入力から同じ結果が出る(決定的)ことが、リプレイ、ゴースト、ロールバック方式のネット対戦の前提になります。
  • 物理エンジンの安定:ばねや拘束は時間刻みが大きくなると発散しやすくなります。刻みを固定すれば、安定するパラメータを一度決めればよくなります。
  • 引っかかり(ヒッチ)対策:読み込みなどで 1 フレームが 0.2 秒になっても、物理は 1/60 秒ずつ進むので、壁のすり抜けが起こりにくくなります。

Unity の FixedUpdate、Unreal の物理サブステッピングが、この仕組みです。

しくみ

Glenn Fiedler の記事「Fix Your Timestep!」で広く知られた形です。

  1. 経過時間をためる:描画 1 回ごとに、実際に経過した時間を「貯金」に足します。
  2. 決まった刻みで消化する:貯金が刻み以上ある間、物理を 1 ステップずつ進めます。60 fps の描画と 60 Hz の物理なら毎回 1 ステップ、30 fps なら 2 ステップ、144 fps なら 0〜1 ステップになります。
  3. 補間して描く:貯金の残りは「まだ物理が追いついていない時間」です。直前の状態と今の状態を、残りの割合 α\alpha で線形補間して描きます。

補間なしで最新の物理の状態をそのまま描くと、描画と物理のタイミングがずれるため、あるフレームでは 2 ステップ分、次のフレームでは 0 ステップ分動く、というばらつきが生じ、カクついて見えます(ジャダー)。

実装のポイント

  • 物理と描画の状態を分ける:補間のために、物理の「前回の状態」と「今回の状態」を両方保持します。描画用の位置は、物理の位置とは別に持ちます。
  • 補間するのは見た目だけ:当たり判定やゲームのロジックは、補間前の物理の状態で行います。
  • 回転はクォータニオンの球面補間:位置は線形補間、回転は球面線形補間で補います。
  • 死のスパイラルを防ぐ:物理 1 ステップの処理が刻みより重いと、貯金が増え続けて処理が追いつかなくなります。1 フレームで消化する回数や、ためる時間に上限を設けます。
  • 入力は物理のステップで読む:ジャンプの入力などを描画フレームで処理すると、ステップ数が 0 のフレームで取りこぼします。入力をためておき、物理のステップで消費します。

つまずきやすい点

  • 補間で 1 ステップ遅れる:補間は「前回と今回の間」を描くので、表示は最大 1 ステップ分だけ過去になります。60 Hz なら約 16 ms で、たいていは問題になりませんが、入力の遅延として気になる場合は外挿(先読み)を使うこともあります。
  • 可変ステップのほうが単純に見える:position += velocity * dt を描画ごとに実行するだけでも動くので、問題に気付くのが遅れがちです。低いフレームレートや引っかかりのある環境でテストします。
  • テレポートは補間しない:リスポーンやワープで位置が大きく飛んだときは、前回の状態も同じ位置にしないと、1 フレームだけ途中の位置が描かれます。

デモで試すこと

  1. 3 つのカプセルは同じジャンプをくり返しています。左下の数値は、本来の高さ(白い点線)に対する直前のジャンプの高さです。赤(可変)は、フレーム時間がばらつくたびに高さが毎回ぶれます。
  2. 黄(固定)と青緑(固定 + 補間)は、いつも同じ高さです。ただし黄は横に進む動きがカクつき、青緑はなめらかです。「再生速度」を下げると違いがはっきり見えます。
  3. 右下の図は、描画(白)と物理の更新(黄)のタイミングです。「描画のフレームレート」と「物理の更新回数」をずらすと、描画 1 回に物理が 0 回や 2 回になるフレームが出てきます。
  4. 「フレーム時間のばらつき・引っかかり」をオフにして、描画 60 fps・物理 60 回/秒にそろえると、3 つとも同じ動きになります。

References

Gaffer On Games — Integration Basics ↗

A general reference for this subcategory.