大きなデルタ時間のための物理シミュレーション方法?


9

非常に大きなデルタ時間(数時間から数週間)に最適な物理シミュレーション方法はどれですか?

さらに、デルタ時間の大小で異なる方法を組み合わせると問題が発生しますか?


1
それはあなたのターゲットエリアに大きく依存します。あなたの本当の目標についてもっと知らなければ、何も言うのは難しいです。広すぎます。
Kromster、2014

この質問は関連しています。
Anko

原則として、適切なタイムスケールは、プレーヤーが体験する内容によって異なります。あなたはそれが数週間の時間スケールで正確になりたいですし、リアルタイムでそれを持つプレイヤーの相互作用を持っていますか?これは、プレーヤーがリアルタイムで何度も体験する数週間のタイムスケールで作業するよりもはるかに困難です(つまり、 1秒のプレーヤー体験は1週間のリアルタイムです)。
mklingen 14

雲の動き、または幅が数百メートルのセル内の熱力学変数を10分のdtでシミュレーションしている場合、それは妥当です。しかし、通常のスケールの剛体は多すぎません。アプリケーションは何ですか?
v.oddou 2014

アプリケーションは、(世界の一部の)最後のロード以降のシミュレーションが実行される「追いつき」メカニズムであり、ゲームロジックはすべてコールバックベースであり、コールバックはタイマーまたは衝突コールバックであり、物理を次に実行できるようにしたいタイマーコールバックを効率的に実行し、物理シミュレーションに衝突コールバックの呼び出しを処理させます。衝突の可能性は比較的低いですが、衝突のコールバックで、衝突時にゲーム(物理)状態を利用できるようにしたいと考えています。
fread2281 2014

回答:


5

おそらく、これらの長い期間(加速度ゼロの可能性があります)には一定の加速度を使用します。時間に対する一定の加速度の微分は0です。つまり、時間に対して変化しないため、デルタ時間の大きさは関係ありません。

時間に関するこの小さな統合は、必要な方程式を提供します。

a = a
v = at + v0
s = .5at^2 + v0*t + s0

ここで:a =加速度、v =速度、v0 =初期速度、s =位置、s0 =初期位置、t =時間

この戦略を使用すると、必要に応じてミリ秒から数週間の時間範囲を使用できます。これらの組み合わせは、方程式のv0およびs0パラメータで処理されます。

衝突を処理するには、高速の小さなオブジェクトに使用されるものと同様の戦略を実装する必要があります。最初に上記の方程式を使用して新しい位置を計算し、次にすべてのオブジェクトの古い位置と新しい位置の間をスイープします。これらのオブジェクトのいずれかが互いに交差する可能性があるため(数分または数日前)、これは非常に複雑になる可能性があります。デルタ時間が非常に大きいため、これらの潜在的な衝突を処理するための十分な時間があることを期待しています。


衝突はどうですか?
fread2281 14

衝突を処理するための戦略を含めるように答えを更新しました。
MichaelHouse

これは誤りです。オイラー積分は定数積分で逸脱することが知られていますが、Verlet(またはRK2、RK4)はそうではありません。
v.oddou 2014

@ v.oddouこれらのシミュレーションはゲーム用であることを考えると、必要な精度は必要ないと思います。Verletに衝突を追加することの追加の複雑さと困難さにより、オイラー統合は優れた選択肢になります。
MichaelHouse

2

重力の例を見てみましょう。

以下の関数では、位置と速度のクラスメンバー変数があると想定しています。重力によって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 すると、必要な忠実度に調整することができます(秒、分、時間、または物理を正確に表すために必要なものに調整できます)。


1

ほとんどのゲームは、順積分の単純なオイラー法を使用する傾向があります(つまり、時間の経過とともに速度を位置に積分し、加速度を速度に積分します)。残念ながら、オイラー法は非常に小さなタイムスケールと短い実行にのみ適しています。

非常に長い時間スケールでより正確な、より複雑な方法があります。最も一般的で実装が最も簡単なのは、おそらくRunge-Kutte-4でしょう。RK4は、過去の4つの位置と速度をサンプリングして補間することにより、将来の位置を決定します。長い時間スケールではオイラー法よりはるかに正確になる傾向がありますが、計算コストが高くなります。

たとえば、数日おきにリアルタイムで更新される実際の軌道を回る惑星の物理を計算する場合、オイラー法では、数値エラーのために数回の軌道で惑星が宇宙に飛び出します。RK4は、一般に、惑星をほぼ同じ形状で数千回周回させてから、エラーを蓄積しすぎます。

ただし、RK4に衝突を実装することは非常に困難です...

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