ひとことで
物体の運動を 1 ステップずつ進めるとき、先に速度を更新し、その新しい速度で位置を進める方法です。位置を先に進める素朴なオイラー法と計算量はまったく同じで、順番を入れ替えただけなのに、軌道が長期間くずれにくく、エネルギーが勝手に増えて発散することもありません。ほとんどのゲームの物理エンジンが、この方法を基本にしています。
ゲームでの使いどころ
- あらゆる動く物:弾、キャラクターのジャンプ、落下物、パーティクル。「速度に加速度を足し、位置に速度を足す」と書けば、それが半陰的オイラー法です。
- 物理エンジンの中身:Box2D、PhysX、Bullet、Unity、Unreal の剛体シミュレーションは、基本的にこの方法(または近いもの)で時間を進めています。
- ばねや軌道の計算:ばね・ダンパーで揺れる物、惑星の公転、振り子など、行ったり来たりする運動で特に差が出ます。
しくみ
時間刻みを 、加速度を とします。
陽的(素朴な)オイラー法は、今の値だけを使って両方を進めます。
半陰的オイラー法(シンプレクティック・オイラー法)は、速度を先に更新し、更新後の速度で位置を進めます。
どちらも 1 ステップの誤差の大きさは同じ(1 次の精度)ですが、誤差のたまり方が違います。
- 陽的オイラー法は、円運動なら毎ステップ接線方向へまっすぐ踏み出すので、必ず円の外側へずれます。ずれは同じ向きに積み重なり、エネルギーが増え続けて軌道が広がり、最後は飛び去ります。ばねなら揺れが毎回大きくなります。
- 半陰的オイラー法は、ある時は外へ、ある時は内へと誤差が行ったり来たりし、長い目で見ると打ち消し合います。エネルギーは少し揺れるだけで、増え続けも減り続けもしません。このように「位相空間の面積を保つ」性質をシンプレクティックといい、長時間のシミュレーションで安定する理由になっています。
実装のポイント
- 力を先に全部集めてから:重力、ばね、推進力など、そのステップで働く力をすべて足し合わせて加速度を出し、それから速度・位置の順に更新します。
- 時間刻みは一定に:誤差の大きさは時間刻みに比例するので、フレームごとに刻みが変わると結果も変わります。固定タイムステップと組み合わせるのが基本です。
- 減衰は速度に掛ける:空気抵抗などは、速度の更新時に
velocity *= 1 - damping * dtのように入れます。
つまずきやすい点
- 順番を逆に書いてしまう:位置を先に更新するコードは一見正しく動くので気付きにくいですが、ばねや軌道でじわじわ発散します。「速度が先」と覚えておきます。
- 硬いばねでは不安定:半陰的オイラー法でも、ばねの固有周期より時間刻みが大きいと発散します(目安は )。硬いばねは刻みを細かくする(サブステップ)か、位置ベース物理を使います。
- 精度が必要なら別の方法:誤差は 1 次なので、弾道の予測線や精密な軌道計算にはルンゲ・クッタ法が向いています。
デモで試すこと
- 「惑星の軌道」では、赤(陽的)が 1 周ごとに外へ膨らみ、やがて飛び去ります。青緑(半陰的)は少しゆがみながらも同じ軌道を回り続け、黄色(正確な解)とほぼ重なります。
- 右下のグラフは、最初のエネルギーからのずれです。赤は増え続け、青緑は 0 の周りで小さく揺れるだけです。
- 「物理の更新回数」を 60 回/秒以上に上げると、陽的オイラー法のずれも小さくなります。刻みを細かくしても根本的な傾向は変わらず、時間をかければ必ず外へずれていきます。
- 「ばねの振動」に切り替えると、陽的オイラー法の箱は揺れがどんどん大きくなり、半陰的オイラー法の箱は同じ幅で揺れ続けます。