非常に大きなデルタ時間(数時間から数週間)に最適な物理シミュレーション方法はどれですか?
さらに、デルタ時間の大小で異なる方法を組み合わせると問題が発生しますか?
非常に大きなデルタ時間(数時間から数週間)に最適な物理シミュレーション方法はどれですか?
さらに、デルタ時間の大小で異なる方法を組み合わせると問題が発生しますか?
回答:
おそらく、これらの長い期間(加速度ゼロの可能性があります)には一定の加速度を使用します。時間に対する一定の加速度の微分は0です。つまり、時間に対して変化しないため、デルタ時間の大きさは関係ありません。
時間に関するこの小さな統合は、必要な方程式を提供します。
a = a
v = at + v0
s = .5at^2 + v0*t + s0
ここで:a =加速度、v =速度、v0 =初期速度、s =位置、s0 =初期位置、t =時間
この戦略を使用すると、必要に応じてミリ秒から数週間の時間範囲を使用できます。これらの組み合わせは、方程式のv0
およびs0
パラメータで処理されます。
衝突を処理するには、高速の小さなオブジェクトに使用されるものと同様の戦略を実装する必要があります。最初に上記の方程式を使用して新しい位置を計算し、次にすべてのオブジェクトの古い位置と新しい位置の間をスイープします。これらのオブジェクトのいずれかが互いに交差する可能性があるため(数分または数日前)、これは非常に複雑になる可能性があります。デルタ時間が非常に大きいため、これらの潜在的な衝突を処理するための十分な時間があることを期待しています。
重力の例を見てみましょう。
以下の関数では、位置と速度のクラスメンバー変数があると想定しています。重力によってdt秒ごとに更新する必要があります。
void update( float dt )
{
acceleration = G * m / r^2;
velocity = velocity + acceleration * dt;
position = position + velocity * dt;
}
dt
ますます小さくなる(場合が、私たちのシミュレーションは、より多くの正確な取得dt
小さすぎるなり、大量に小さな数字を追加するとき、我々は精度エラーが発生することができます)。
基本的に、dt
十分な結果を得るためには、シミュレーションで処理できる最大値を決定する必要があります。そしてdt
、それが大きすぎる場合は、シミュレーションをより小さなステップに分割します。各ステップは、dt
許可する最大値です。
void update( float dt )
{
acceleration = G * m / r^2;
velocity = velocity + acceleration * dt;
position = position + velocity * dt;
}
// this is the function we call. The above function is a helper to this function.
void updateLargeDt( float dt )
{
const float timeStep = 0.1;
while( dt > timeStep )
{
update( timeStep );
dt -= timeStep ;
}
update( dt ); // update with whatever dt is left over from above
}
したがって、この戦略を使用timeStep
すると、必要な忠実度に調整することができます(秒、分、時間、または物理を正確に表すために必要なものに調整できます)。
ほとんどのゲームは、順積分の単純なオイラー法を使用する傾向があります(つまり、時間の経過とともに速度を位置に積分し、加速度を速度に積分します)。残念ながら、オイラー法は非常に小さなタイムスケールと短い実行にのみ適しています。
非常に長い時間スケールでより正確な、より複雑な方法があります。最も一般的で実装が最も簡単なのは、おそらくRunge-Kutte-4でしょう。RK4は、過去の4つの位置と速度をサンプリングして補間することにより、将来の位置を決定します。長い時間スケールではオイラー法よりはるかに正確になる傾向がありますが、計算コストが高くなります。
たとえば、数日おきにリアルタイムで更新される実際の軌道を回る惑星の物理を計算する場合、オイラー法では、数値エラーのために数回の軌道で惑星が宇宙に飛び出します。RK4は、一般に、惑星をほぼ同じ形状で数千回周回させてから、エラーを蓄積しすぎます。
ただし、RK4に衝突を実装することは非常に困難です...