TT Lab
はじめる
学ぶ 学習パス コース

物理エンジンの骨組み

オイラー法はなぜエネルギーを増やすのか

TT Labで続きを見る

一言でいうと

加速度から速度を、速度から位置を求める方法は、いくつもありますが、陽的オイラー法は、振動する系で、1ステップごとにエネルギーを少しずつ足していきます。順序だけを変えた半陰的オイラー法は、そうなりません。

なぜ必要なのか

物理エンジンが解くのは、微分方程式です。力から加速度が出て、加速度を時間で積分すれば速度が、速度を積分すれば位置が出ます。コンピューターは、連続的な積分をできないので、時間を細かく区切って近似します。

問題は、その近似が、誤差を出すだけでなく、系の性質そのものを変えてしまうことです。ばねにつながれた重りは、永遠に同じ幅で振動するはずなのに、最も単純な方法で計算すると、振幅がだんだん大きくなって、数秒で画面の外に飛んでいきます。力の計算が間違っているのではなく、積分の方法が間違っているのです。

どう動くのか

陽的オイラー法は、1ステップの開始時点の値だけを使います。

x_new = x + v * dt
v_new = v + a(x) * dt

ばね(a = -x、質量と剛性が1)に入れると、1ステップが線形変換になり、その変換の拡大率を、正確に計算できます。エネルギーE = (x² + v²)/2は、毎ステップ、ちょうど(1 + dt²)倍になります。dt=0.05で400ステップなら、1.0025^400 ≈ 2.715倍です。誤差ではなく、体系的な増加です。dtを小さくすると、遅くなるだけで、方向はそのままです。

半陰的(シンプレクティック)オイラー法は、順序だけを変えます。

v_new = v + a(x) * dt
x_new = x + v_new * dt        # 방금 구한 새 속도를 쓴다

一行の順序を変えただけなのに、性質がまったく変わります。この方法は、元のエネルギーに非常に近い別の量を正確に保存し、そのため、エネルギーが小さな幅で振動するだけで、発散しません。ゲームの物理エンジンが、ほとんどすべてこれを使う理由です。計算コストは、陽的オイラー法とまったく同じです。

速度ヴェルレ法は、1ステップの中で、加速度を2回使います。

x_new = x + v * dt + 0.5 * a * dt²
a_new = a(x_new)
v_new = v + 0.5 * (a + a_new) * dt

精度が1次高いので(dtの2次)、同じdtで誤差がはるかに小さく、シンプレクティックの性質も保ちます。分子動力学のように、長い時間を正確に回す必要がある所で、標準です。その代わり、ステップごとに力の計算が1回余計に入ります。

ここで重要なのは、精度と安定性は別の軸だという点です。陽的オイラー法の問題は、正確ではないことではなく、時間がたつほど悪くなる方向が決まっていることです。

なぜ順序1つでこれほど大きな違いが生まれるのかを、もう少し覗いてみる価値があります。陽的オイラー法の1ステップを行列で書くと、その行列の行列式が1 + dt²で、1より大きくなります。行列式は、位相空間で面積が何倍になるかを意味するので、毎ステップ、状態空間が少しずつ膨らんでいきます。半陰的オイラー法の行列式は、ちょうど1です。面積を保存する変換なので、発散のしようがありません。シンプレクティックという言葉が意味するのは、この性質です。

1つ、誤解を正しておきます。シンプレクティックな積分器が保存するのは、エネルギー自体ではありません。元のエネルギーに非常に近い別の量を正確に保存し、その結果、エネルギーが小さな幅で上下するだけで、一方向に流れていきません。そのため、ラボで、半陰的オイラー法のエネルギー曲線は、平らな直線ではなく、薄く振動する帯として出ます。それが正常です。

現場での姿

可変の時間間隔が、事故を招きます。フレームが一度遅れて、dtが大きくなると、そのステップで、物体が壁を通り抜けたり、拘束が爆発したりします。そのため、物理エンジンは、レンダリングと物理を分離して、固定dtで物理を回し、余った時間の分だけ、ステップ数を調節します。dtを大きくする代わりに、複数のステップを回すのです。

もう1つは、減衰を真似るために、毎ステップ、速度に0.99を掛ける方式です。簡単で、実際に安定を助けますが、減衰量がdtによって変わるので、フレームレートが異なる機械で、物体が異なる動きをします。物理的に正しい方法は、減衰を力として入れることです。

最後に、実行順序についての、実務上のルールが1つあります。物理のステップの中では、力の適用、速度の更新、衝突の解決、位置の更新の順序が決まっている必要があり、その順序を、コードの複数の場所で少しずつ違えると、再現できません。同じ入力が同じ結果を出さないシミュレーションは、デバッグがほとんど不可能になります。バグを再現できないからです。ネットワークゲームで、サーバーとクライアントが同じ計算をする必要がある場合には、この再現性が、そもそも要件になります。

そして、積分器を選ぶときの、実用的な基準は、次のとおりです。ゲームのように、もっともらしく見えればよく、長く動かし続ける必要がある場合は、半陰的オイラー法が、ほとんどいつも正解です。値が正確でなくても、発散しないことのほうが、はるかに重要だからです。一方、軌道の計算や分子動力学のように、数値そのものが結果である場合は、ヴェルレ法や、それ以上の方法を使います。

次のラボですること

同じばねを、3種類の積分器で400ステップ回して、それぞれのエネルギーをCSVに残し、3本の曲線を1枚のPNGに描いて、オイラー法だけが上に跳ね上がることを、目で見ます。次に、dtを変えながら、エネルギーの増加率が、閉じた式(1 + dt²)^nと合っているかを確認し、最後に、減衰を力として入れて、エネルギーが単調に減ることを見ます。