球と平面の間の衝突応答を計算するにはどうすればよいですか?


9

シンプルな3Dゲームを作成しようとしています。ゲームの世界の制限内でプレーヤーを制限する必要があります。プレイヤーが世界の側面にぶつかったとき、プレイヤーの船を少し跳ね返らせたいです。

事実、私はプレイヤーをボックス内に閉じ込め、側面から逃げるのを止めようとしています...

ゲームワールドの限界を、法線と原点からの距離を持つ平面のコレクションとして定義できました。プレーヤーには球形の境界球があり、このウェブサイトhttp://www.gamasutra.com/view/feature/3383/simple_intersection_tests_for_games.phpから衝突を検出することができました。

衝突が検出されたときにどうすればよいのか、私はまったく理解できません。私が管理できる最高の方法は、プレイヤーが飛行機に詰まっている、まっすぐ進む、または非常に速い速度で繰り返し跳ね返ることです。

常識では、法線を使用して平面からの反射角度を計算し、それをプレーヤーの速度に適用する必要があると言われていますが、まず、プレーヤーが平面を通過したかどうかを確認する必要があります。いい結果になる。

回答:


4

オブジェクトにインパルスを適用する必要があります。これは、オブジェクトの速度が即座に変化するためです。現実の世界では、非常に短いタイムステップで強力な力がオブジェクトに適用され、加速度が逆転して速度が変化します。ただし、私たちは離散的な世界で作業しているため、この突然の方向の変化をシミュレートするために少しチートする必要があります。球と平面の場合、それはかなり簡単です。最も基本的な衝突応答は、平面の法線の周りの球の速度を反映することであり、結果は球の新しい速度になります。疑似コードは次のようになります。

reflected = 2 * plane.normal * (plane.normal * sphere.velocity)
sphere.velocity -= reflected

そこから、ダンピングを追加(0.9などの係数を掛ける)して、熱や摩擦によって失われるエネルギーを考慮することができます。角速度を取得したい場合(おそらく球が回転している場合)、方程式は少し複雑になります。

詳細については、Rigid Body Dynamicsに関するChris Heckerの記事を参照します。クリス・ヘッカーのことを聞いたことがなければ、彼はゲームの物理学と、胞子での手続き型キャラクターの生成とアニメーションでの彼の仕事で有名です。


4
これは基本的に正しい方法ですが、インパクトタイム(TOI)を計算すると、フレームレートが変動または低下するため、より正確になります。現在の速度に基づいて、どのくらい前にインパクトが発生したかを知ることは、インパクトの時間を計算するのに役立ち、それを使用して、インパクトの瞬間に球をその位置に戻し、そこから速度を調整できます。インパクトの時点から位置と速度を調整した後、インパクト時に、減算した時間だけ新しい速度に沿ってTOIに移動します。
ニックフォスター

OKこれはほとんど機能するようですが、少し奇妙です。私のコードの間違ったポイントでこれを行っている可能性があります。すべてのオブジェクトをループして、オブジェクトが移動する前に(次のフレームになる場所に基づいて)衝突するかどうかをテストするか、オブジェクトを移動してから衝突をテストする必要がありますか?
ピク

@Piku、それらが衝突するかどうかを検出しません。衝突が発生した場合、2つのオブジェクトが実際の衝突が発生した場所をはるかに超えてオーバーラップしている可能性が非常に高いことを覚えておいてください。基本的に、無限のフレームレート(そうではない)があるかのように衝突が発生した場所を特定し、最初に衝突が発生した位置にオブジェクトを戻す必要があります。このようにオブジェクトを分離しないと、同じ衝突に継続的に反応し、オブジェクトが動かなくなります。
ジョナサンディキンソン

@Pikuとそのために、衝突が発生した過去の時間(TOI /衝突時間)を特定します。それができたら、オブジェクトの速度を使用してオブジェクトを戻し(distance = speed * time通常、エラーを回避するために非常に短い距離で)、速度を衝突の結果に更新します。
ジョナサンディキンソン

@Pikuでは、次のフレームのどこにあるかはわかりませんが(個人的に行ったことはありません)、通常は、衝突の検出と応答を行います。このフレームの新しい位置を計算した後、その前にこのフレームに新しい位置を適用します。
ジョナサンディキンソン

1

F = ma、またはa = F / m。球と平面の間の衝突点を計算します。これは通常、球の中心-通常の半径です。より正確にしたい場合は、球が平面をどのくらい貫通したかを計算し、計算を調整します。本当に正確な物理学が必要でない限り、これはもちろんオプションです。次に、法線に沿った相対速度を計算します。静的平面の場合、これはVball Dot Nです。次に、VballDotNに-1を掛け、質量を掛けます。この段階の物理学では、これに反発係数(バウンス係数)を掛けます。このスカラーにNを乗算すると、あなたの力が得られます。

Vballを調整する場合は、力を質量で除算すると最終的な加速度が得られるので、これを速度に追加するだけで、最終的な衝突後の速度が得られます。

vec3 Vrel = Ball.getVelocity();
float vDotN = Vrel.Dot(CollisionNormal);
vec3 F = -(1.0f+Ball.getRestitution())*vDotN;
F*=Ball.getMass();
Ball.accelerate(F/Ball.getMass());

この方法は、衝突応答の式に対して正確です。さらに正確にしたい場合は、摩擦を考慮に入れる必要があります。これにより、ボールがスピンしますが、ゲームでそれが必要かどうかはわかりません。その場合、これは接線力を計算する方法です。

vec3 Ft = -(Ball.getvelocity()+(vDotN*CollisionNormal));
Ft*=Ball.getKineticFriction()+Wall.getKineticFriction(); //you could fudge these numbers
Ft*=Ball.getMass();
vec3 vec2Centre = Ball.getPosition()-ContactPoint;
vec3 Torque = cross(vec2Centre,Ft);
Ball.AngularAccelerate(Torque/Ball.getMomentofInertia(glm::normalize(Torque)));

線形効果を適用する前にFtを計算してください。そうしないと、摩擦が正確になりません。


3行目は次のようにすべきではありませんvec3 F = -CollisionNormal * (1.0f+Ball.getRestitution())*vDotN;
Shital Shah

確かにそうです、その部分を逃しました。指摘してくれてありがとう。
イアンヤング

0

最初に飛行機からの距離を計算することをお勧めします。そして半径までの距離が衝突反応を実行します。

次に、これを変更して距離を計算し、距離がその半径(オブジェクトがオーバーラップしていることを意味する)より小さい場合は、ボールの位置をシフトして、衝突反応を実行します。

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