9

この質問には、1 つの大きな質問と 1 つの小さな質問があります。私は自分の研究からどちらの質問でも正しいと信じていますが、両方ではありません。

私の物理ループでは、最初にTotalForce剛体オブジェクトに重力を適用します。TotalForce次に、 myと myを使用して衝突をチェックしVelocityます。Myは物理ループごとに にTotalForceリセットされますが、 .(0, 0, 0)velocity

速度のみを使用する場合に、移動する球体と静的平面の間の衝突チェックを行うことに慣れています。velocityしかし、重力など、以外の力がある場合はどうなるでしょうか。他の力を入れましたTotalForces(今は重力しかありません)。それを補うために、球が現在平面に重なっていないと判断した場合は、

    Vector3 forces = (sphereTotalForces + sphereVelocity);
    Vector3 forcesDT = forces * fElapsedTime;
    float denom = Vec3Dot(&plane->GetNormal(), &forces);

ただし、これは、連絡を取り合っていると私が思っていた方法にとって問題になる可能性があります。安静時の接触は次のように計算されたと思いました

denom * dist == 0.0f

どこdistですか

float dist = Vec3Dot(&plane->GetNormal(), &spherePosition) - plane->d;

(参考までにdenom * dist > 0.0f、球が平面から離れているという明白な意味)

ただし、これは決して真実ではありません。「安静時の接触」があるように見える場合でも。これは、forces上記の私の計算では常に少なくとも .y が -9.8 (私の重力) であるためです。法線が (0, 1, 0) の平面に向かって移動するとdenom、-9.8 の y が生成されます。

私の質問は

1) 最初の 2 つのコード スニペットで述べた方法で、静止接触を正しく計算していますか?

もしそうなら、

2) 重力などの「その他の力」はどのように使用すればよいですか? 私の使い方はTotalForces間違っていますか?

参考までに、私のタイムステップは

  mAcceleration = mTotalForces / mMass;
  mVelocity += mAcceleration * fElapsedTime;
  Vector3 translation = (mVelocity * fElapsedTime);

編集

いくつかの提案された変更が衝突コードを変更するように見えるので、衝突状態を検出する方法は次のとおりです

if(fabs(dist) <= sphereRadius)
{ // There already is a collision }
else
{
    Vector3 forces = (sphereTotalForces + sphereVelocity);
    float denom = Vec3Dot(&plane->GetNormal(), &forces);

    // Resting contact
    if(dist == 0) { }
    // Sphere is moving away from plane
    else if(denom * dist > 0.0f) { }
    // There will eventually be a collision
    else
    {
        float fIntersectionTime = (sphereRadius - dist) / denom;
        float r;
        if(dist > 0.0f)
            r = sphereRadius;
        else
            r = -sphereRadius;

        Vector3 collisionPosition = spherePosition + fIntersectionTime * sphereVelocity - r * planeNormal;
    }
}
4

6 に答える 6

1
  1. if(fabs(dist) < 0.0001f) { /* collided */ }This is を使用して、浮動小数点の精度を説明する必要があります。ほとんどの角度または接触で正確な 0.0f を得ることはまずありません。

  2. 負の場合の値distは、実際には、ボディがプレーン サーフェスを通過する場合にボディをプレーン サーフェスに戻すために必要な実際の量です。sphere.position = sphere.position - plane.Normal * fabs(dist);

  3. サーフェスに戻したら、必要に応じてプレーン法線に対して反対方向にバウンドさせることができます。または飛行機にとどまります。

    parallel_vec = Vec3.dot(plane.normal, -sphere.velocity);

    perpendicular_vec = sphere.velocity - parallel_vec;

    bounce_velocity = parallel - perpendicular_vec;

  4. totalforce = external_force + velocityすべてに単位質量がなければ、やみくもに行うことはできません。

編集

  1. 3D 空間で平面を完全に定義するには、平面構造に平面法線ベクトルと平面上の点を格納する必要があります。http://en.wikipedia.org/wiki/Plane_(geometry ) .

Vector3 planeToSphere = sphere.point - plane.point;

float dist = Vector3.dot(plane.normal, planeToSphere) - plane.radius;

if(dist < 0) { // collided. }

これがあなたの知らない部分である場合は、最初にもっと数学を勉強することをお勧めします.

注意: 申し訳ありませんが、書式設定がめちゃくちゃです... コード ブロックとしてマークできません。

EDIT 2 : コードに関する私の理解に基づいて、変数の名前が間違っているか、前述のように、数学と物理学の理論を修正する必要があります。この行は何も役に立ちません。

float denom = Vec3Dot(&plane->GetNormal(), &forces);

いつでも、球にかかる力は、進行方向とはまったく関係のない任意の方向にある可能性があります。そのため、denom は基本的に平面の方向の力の量を計算しますが、ボールが平面に当たるかどうかについては何も教えてくれません。たとえば、重力は下向きですが、ボールは上向きの速度を持ち、上の平面にぶつかることがあります。それで、Vec3Dot(plane.normal, velocity)代わりにする必要があります。

あるいは、Mark Phariss と Gerhard Powell が線形運動学の物理方程式を既に与えていたので、それらを使用して、将来の位置、速度、衝突の時間を直接計算できます。

たとえばs = 0.5 * (u + v) * t;、将来の時刻 t の後の変位を返します。その変位を平面からの距離と比較すると、球が平面に衝突するかどうかがわかります。繰り返しになりますが、http: //en.wikipedia.org/wiki/Linear_motionを読んで、最初に簡単なものを読んでからhttp://en.wikipedia.org/wiki/Kinematicsを読むことをお勧めします。

さらに別の方法として、他の力が球に作用しないと予想または仮定する場合は、光線/平面衝突テストを実行して、平面に衝突する時間 t を見つけます。その場合は、http://enを参照してください。 .wikipedia.org/wiki/Line-plane_intersection .

于 2012-05-09T08:51:28.367 に答える
0

その後、erin catoの記事(Box2Dの作者)とGlennfiedlerの記事も見てみることをお勧めします。重力は強い加速であり、強い力をもたらします。浮動不正確さ、可変タイムステップ、オイラー積分のために、シミュレーションに問題が発生するのは簡単です。球が平面を通過したときにそれ自体がバタバタし始めた場合の平面での球の再配置は必須です。球の速度が平面の法線と反対である場合にのみ行う方がよいことに気づきました(これは比較できます) 3Dレンダリングでカリングに直面するには:背面の平面を考慮しないでください)。

また、ほとんどの物理エンジンはアイドル状態のボディでシミュレーションを停止し、ほとんどのゲームは移動中は重力を考慮せず、落下した場合にのみ考慮します。シミュレートされたオブジェクトがその「地面」に付着していることが確実である限り、「ナビゲーションメッシュ」とカスタムシステムを使用します。

私はそこに完璧な物理シミュレーターを知りません、常に統合爆発、逃した衝突(「スイープ衝突」を探してください)があります...それは多くの経験的な微調整を必要とします。

また、衝突時に速度を手動で微調整することを回避する方法である「インパルス」を探すことをお勧めします。

また、「すべてのコンピューター科学者がフローティングポイントについて知っておくべきこと」も参照してください。

幸運を祈ります。あなたは地雷原に入りました。ランダムに理解できない、数値計算機科学の指を噛む領域です:)

于 2012-05-14T10:03:37.450 に答える
0

この問題の正確な解決策には、かなり深刻な数学が含まれます。おおよその解決策が必要な場合は、段階的に開発することを強くお勧めします。

1)シムが重力なしで動作することを確認します。ボールは空間を移動し、角度のある摩擦のない表面と非弾性(または部分的に弾性)の衝突を起こす必要があります。

2)重力を導入します。これにより、弾道が直線から放物線に変わり、スライドが発生しますが、衝突にはあまり影響しません。

3)静摩擦と動摩擦を(独立して)導入します。これらは、スライドのダイナミクスを変更します。今のところ、衝突時の摩擦について心配する必要はありません。

4)ボールの角速度と慣性モーメントを与えます。これは大きな一歩です。それにトルクを加えて、現実的な角加速度を得ることができることを確認してください。回転する質量の現実的な動作は、直感に反する可能性があることに注意してください。

5)重力の下で、水平面に沿ってボールをスライドさせてみてください。すべてを正しく行うと、角速度は徐々に増加し、線速度は徐々に減少し、ロールに分割されます。ボールに最初のスピン(「ドロー」、「フォロー」、「英語」)を与えてみてください。

6)同じことを試してください。ただし、傾斜面で行ってください。これは比較的小さなステップです。

ここまで到達すると、かなりリアルなシムが得られます。手順をスキップしようとしないでください。頭痛の種になるだけです。

于 2012-05-10T13:30:29.717 に答える
0

球には常に -9.8y の重力が作用します。吊り下げられた球体の場合、これは下向きの加速になります (正味の力はゼロではありません)。平面上にある球の場合、これは平面が球に垂直な力を及ぼす結果となります。静止している球体に対して平面が完全に水平である場合、この法線の力は正確に +9.8y になり、重力を完全に打ち消すことになります。非水平面に静止している球体の法線力は9.8y * cos(angle)(角度は -90 度から +90 度の間) です。

法線力は速度と平面/球体のプロパティに依存するため、移動する球体が平面に衝突すると、事態はさらに複雑になります。アプリケーションの要件に応じて、これを無視するか、通常の力でいくつかのことを試して、それがどのように機能するかを確認できます。

具体的な質問について:

  1. 接触は、より具体的にdist == 0.0fは 、つまり球と平面が接触しているときだと思います。あなたの衝突は、物理的な時間ステップで球が平面を通過する可能性があることを考慮していると思います。
  2. 現時点では、球体が接触しているときに、平面から球体に垂直な力がかかっているようには見えません。これを行うには、接触 ( ) をチェックしdist == 0.0f、真の場合は球に法線力を追加します。球体がほぼ水平面 (-90 度から +90 度の間の角度) に落下するという単純なケースでは、ちょうど になりますsphereTotalForces += Vector3D(0, 9.8 * cos(angle), 0)

編集:

ここから、球の端から平面までの距離を計算するための式distは、問題とコードの詳細によっては正しくない場合があります (これは指定されていません)。平面が原点を通過すると仮定すると、正しい方程式は次のようになります。

dist = Vec3Dot(&spherePosition, &plane->GetNormal()) - sphereRadius;

これは、式 if と同じですplane->d == sphereRadius。平面が原点にない場合は、次を使用することに注意してください。

D3DXVECTOR3 vecTemp(spherePosition - pointOnPlane);
dist = Vec3Dot(&vecTemp, &plane->GetNormal()) - sphereRadius;
于 2012-05-01T11:53:54.627 に答える
0

物理の問​​題に対する答え:

f = mg + other_f; // m = mass, g = gravity (9.8)
a = f / m; // a = acceleration
v = u + at; // v = new speed, u = old speed, t = delta time
s = 0.5 * (u + v) *t;

衝突が発生した場合は、両方の速度を 0 に変更します (または、跳ね返らせたい場合は v と u = -(u * 0.7))。

速度 = 0 なので、ボールは静止しています。

2D または 3D の場合は、サーフェスの法線方向の速度を 0 に変更し、平行速度を同じに保ちます。その結果、ボールが表面を転がります。

ボールが表面をカットする場合は、ボールを表面に移動する必要があります。衝突距離を小さい値 (たとえば 0.001) にして、確実に動かないようにすることができます。

http://www.physicsforidiots.com/dynamics.html#vuat

編集:

NeHe はゲーム エンジン設計の驚くべき情報源です。非常に適切な説明が記載された衝突検出に関するページがあります: http://nehe.gamedev.net/tutorial/collision_detection/17005/

編集2:(NeHeから)

double DotProduct=direction.dot(plane._Normal); // Dot Product Between Plane Normal And Ray Direction
Dsc=(plane._Normal.dot(plane._Position-position))/DotProduct; // Find Distance To Collision Point
Tc= Dsc*T / Dst
Collision point= Start + Velocity*Tc
于 2012-05-09T22:51:11.743 に答える
-1

忠実度を高めるために(主な問題は解決しません)、タイムステップを次のように変更します

mAcceleration = mTotalForces / mMass;
Vector3 translation = (mVelocity * fElapsedTime) + 0.5 * mAcceleration * pow(fElapsedTime, 2);
mVelocity += mAcceleration * fElapsedTime;

球体は剛体だとおっしゃいました。飛行機も剛体としてモデル化していますか?もしそうなら、あなたは接触の瞬間に無限の力を持ち、運動量の明示的な散逸なしに完全に弾性衝突します。

力と速度を合計することはできません (互換性のない単位)。運動学をモデル化しようとしているだけの場合は、質量を無視して、加速度と速度のみで作業できます。

球が完全に非弾性の衝突 (バウンスなし) で水平面に単純にドロップされると仮定すると、[NB、私は C 構文を本当に知らないので、これは Pythonic になります] を行うことができます。

mAcceleration = if isContacting then (0, 0, 0) else (0, -9.8, 0)

衝突にいくらかの弾力性(半分の運動量保存など)を追加すると、より似たものになります

mAcceleration = (0, -9.8, 0) + if isContacting then (0, 4.9, 0)
于 2012-05-03T17:56:22.993 に答える