衝突エンジンはどのように機能しますか?


78

衝突エンジンはどのくらい正確に機能しますか?

これは非常に広範な質問です。どのコードが物事をお互いにバウンドさせ続けますか、どのコードがプレーヤーを壁の中を歩くのではなく壁の中に入れますか?重力と衝突が正常に機能するように、コードはどのようにプレーヤーの位置とオブジェクトの位置を常に更新しますか?

衝突エンジンが何であるかわからない場合、基本的にはプラットフォームゲームでプレイヤーが実際に壁などにぶつかるようにするために使用されます。2Dタイプと3Dタイプがありますが、それらはすべて同じことを行います:衝突。

それでは、衝突エンジンが刻々と変化するのはなぜでしょうか?


3
バウンディングボックスと球体でカンニングをすることができます。それらの交点は高速に判別できます。その後、より詳細に検査できます。cs.unc.edu/~dm/collision.html en.wikipedia.org/wiki/Collision_detection ナイーブアルゴリズムを使用すると、これを常にゆっくりと行うことができます。Comp Geometryには、問題の幾何学的性質を利用してアルゴリズムを高速化するいくつかのトリックがあります。ここで非常に良い論文は次のとおりです。cs.hku.hk/research/techreps/document/TR-2005-01.pdf

衝突エンジンとは何ですか?

4
@gnat衝突エンジンは基本的にゲーム(一般的に)で使用されるエンジンであるため、プレーヤー(ボブと呼ぶ)は、ボブが壁に移動するたびに、ボブが停止し、ボブは壁を通り抜けません。また、一般的に、ゲームの重力やそのような環境のことも処理します。
JXPheonix

回答:


172

衝突エンジンと物理エンジンには大きな違いがあります。物理エンジンは一般に衝突エンジンに依存していますが、それらは同じことを行いません。

衝突エンジンは、衝突検出と衝突応答の2つの部分に分割されます。後者は一般に物理エンジンの一部です。これが、衝突エンジンと物理エンジンが通常同じライブラリに組み込まれている理由です。

衝突検出には、離散と連続の2つの形式があります。高度なエンジンは、プロパティが異なるため、両方をサポートしています。一般に、連続衝突検出は非常に高価であり、本当に必要な場合にのみ使用されます。衝突と物理の大部分は、個別の方法を使用して処理されます。個別の方法では、オブジェクトは相互に浸透し、物理エンジンはそれらを引き離すように働きます。そのため、エンジンは実際にはプレイヤーが壁や床を部分的に歩くのを止めず、プレイヤーが部分的に壁/床にいることを検出した後にそれを修正します。ここでは、離散衝突検出に焦点を当てます。これは、ゼロから実装するのが最も経験が豊富なためです。

衝突検出

衝突検出は比較的簡単です。すべてのオブジェクトには、変換とシェイプ(複数のシェイプがあります)があります。素朴なアプローチでは、衝突エンジンにすべてのオブジェクトペアを介してO(n ^ 2)ループを実行させ、ペア間に重複があるかどうかをテストします。よりスマートなアプローチでは、複数の空間データ構造(静的オブジェクトと動的オブジェクトなど)、各オブジェクトの境界形状、各オブジェクトのマルチパート凸サブ形状があります。

空間データ構造には、KDツリー、ダイナミックAABBツリー、オクトリー/クアッドツリー、バイナリスペースパーティションツリーなどが含まれます。それぞれに長所と短所があるため、一部のハイエンドエンジンは複数のエンジンを使用します。たとえば、ダイナミックAABBツリーは非常に高速で移動する多くのオブジェクトの処理に適していますが、KDツリーはオブジェクトが衝突する静的レベルのジオメトリにより適している場合があります。他のオプションもあります。

ブロードフェーズでは、空間データ構造と各オブジェクトの抽象的な境界ボリュームを使用します。バウンディングボリュームは、オブジェクト全体を囲む単純な形状であり、一般に、衝突テストを安価にしながら、できるだけ「密に」オブジェクトを囲むことを目的としています。最も一般的な境界形状は、軸に沿った境界ボックス、オブジェクトに沿った境界ボックス、球、およびカプセルです。AABBは一般に最速かつ最も簡単であると考えられています(球体は場合によってはより簡単で高速ですが、それらの空間データ構造の多くはいずれにしても球体をAABBに変換する必要があります)が、多くのオブジェクトにかなり適合しない傾向があります。カプセルは、キャラクターレベルの衝突を処理するための3Dエンジンで一般的です。一部のエンジンは2つの境界形状を使用しますが、

衝突検出の最後のフェーズは、ジオメトリが交差している場所を正確に検出することです。これは通常、メッシュ(または2Dのポリゴン)を使用することを意味しますが、常にではありません。このフェーズの目的は、オブジェクトが実際に衝突するかどうか、細かいレベルの詳細が必要かどうかを確認することです(たとえば、シューティングゲームでの弾丸の衝突。また、オブジェクトが衝突する場所を正確に見つけることもできます。これは、オブジェクトの応答方法に影響します。たとえば、ボックスがテーブルの端にある場合、エンジンはテーブルがボックスを押しているポイントを知る必要があります。箱がどの程度垂れ下がっているのかによって、箱が傾き始めたり落ちたりすることがあります。

マニホールド生成に連絡する

ここで使用されているアルゴリズムには、一般的なGJKおよびMinkowskiポータルの洗練アルゴリズム、および軸分離テストが含まれます。一般に、一般的なアルゴリズムは凸形状に対してのみ機能するため、多くの複雑なオブジェクトを凸サブオブジェクトに分割し、それぞれ個別に衝突テストを行う必要があります。これは、単純化されたメッシュが衝突によく使用される理由の1つであり、使用する三角形を少なくするための処理時間の短縮にもなります。

これらのアルゴリズムの一部は、オブジェクトが確実に衝突したことを知らせるだけでなく、衝突した場所、つまり相互に貫通している距離と「接点」とは何かを示します。一部のアルゴリズムでは、この情報を取得するために、ポリゴンクリッピングなどの追加の手順が必要です。

身体的反応

この時点で、コンタクトが発見されており、物理エンジンがコンタクトを処理するのに十分な情報があります。物理処理は非常に複雑になる可能性があります。より単純なアルゴリズムは一部のゲームで機能しますが、ボックスのスタックを安定に保つことのように一見簡単に見えるものでさえ、非常に困難であることが判明し、多くの作業と非自明なハックが必要です。

最も基本的なレベルでは、物理エンジンは次のような処理を行います。衝突するオブジェクトとその接触多様体を取得し、衝突するオブジェクトを分離するために必要な新しい位置を計算します。オブジェクトをこれらの新しい位置に移動します。また、このプッシュに起因する速度の変化を、反発(弾力性)および摩擦の値と組み合わせて計算します。物理エンジンは、重力など、オブジェクトに作用する他の力も適用して、オブジェクトの新しい速度を計算し、(次のフレーム)新しい位置を計算します。

より高度な物理応答はすぐに複雑になります。上記のアプローチは、1つのオブジェクトが他の2つのオブジェクトの上にあるなど、多くの状況で機能しなくなります。各ペアを単独で処理すると、「ジッター」が発生し、オブジェクトが大きく跳ね返ります。最も基本的な手法は、衝突するオブジェクトのペアに対して多数の速度補正反復を行うことです。たとえば、ボックス「A」が他の2つのボックス「B」および「C」の上にある場合、衝突ABが最初に処理され、ボックスAがさらにボックスCに傾きます。次に、AC衝突が夕方に処理されますボックスを多少外しますが、AをBに引き下げます。その後、別の反復が行われるため、AC補正によって引き起こされたABエラーはわずかに解決され、AC応答にもう少しエラーが生じます。ACが再び処理されるときに処理されます。実行される反復の数は固定されておらず、それが「完全」になるポイントはありませんが、反復の回数に関係なく、意味のある結果が得られなくなります。10回の反復は典型的な最初の試みですが、特定のエンジンと特定のゲームのニーズに最適な数を見つけるには微調整が必​​要です。

連絡先キャッシング

多くのタイプのゲームを扱うときに、本当に便利な(多かれ少なかれ必要な)ことが判明した他のトリックがあります。連絡先のキャッシュは、より便利なものの1つです。連絡先キャッシュでは、衝突するオブジェクトの各セットがルックアップテーブルに保存されます。各フレームでは、衝突が検出されると、このキャッシュが照会され、オブジェクトが以前に接触していたかどうかが確認されます。オブジェクトが以前に接触していなかった場合は、「新しい衝突」イベントを生成できます。オブジェクトが以前に接触していた場合、その情報を使用してより安定した応答を提供できます。フレーム内で更新されなかった連絡先キャッシュのエントリは、分離した2つのオブジェクトを示し、「オブジェクトの分離」イベントを生成できます。多くの場合、ゲームロジックはこれらのイベントを使用します。

また、ゲームロジックが新しい衝突イベントに応答し、無視されたものとしてフラグを立てることも可能です。これは、ジャンプして立ち上がることができるプラットフォームなど、プラットフォームで一般的ないくつかの機能を実装するのに非常に役立ちます。素朴な実装では、下向きのプラットフォーム->キャラクターの通常の衝突(プレイヤーの頭がプラットフォームの底に当たることを示す)を単に無視するかもしれませんが、コンタクトキャッシングなしでは、プレイヤーの頭がプラットフォームを突き抜けてから開始すると中断します落ちる。その時点で、接触法線が最終的に上向きになり、プレイヤーがプラットフォームを飛び越えてしまうはずです。連絡先キャッシュを使用すると、エンジンは初期衝突法線を確実に確認し、プラットフォームとプレーヤーが再び分離するまで、以降のすべての連絡イベントを無視できます。

睡眠

別の非常に便利な手法は、オブジェクトが対話されていない場合にオブジェクトを「スリープ状態」としてマークすることです。眠っているオブジェクトは物理的な更新を取得せず、他の眠っているオブジェクトと衝突せず、基本的には、眠っていない別のオブジェクトが衝突するまで時間内にそのまま座っています。

その影響は、何もせずにただ座っている衝突オブジェクトのすべてのペアが処理時間を消費しないことです。また、一定の量の小さな物理補正がないため、スタックは安定します。

オブジェクトは、複数のフレームで速度がほぼゼロになっている場合にスリープする候補です。このほぼゼロの速度をテストするために使用するイプシロンは、通常の浮動小数点比較イプシロンよりも少し高くなることに注意してください。スタックされたオブジェクトで多少のジッターが予想されるため、オブジェクトのスタック全体がスリープ状態になる場合安定した状態に「十分に近い」状態を維持します。もちろん、しきい値には調整と実験が必要です。

制約

多くの物理エンジンの最後の主要な部分は、制約ソルバーです。このようなシステムの目的は、バネ、モーター、ホイール軸、シミュレートされたソフトボディ、布、ロープ、チェーン、さらには流体のようなものの実装を容易にすることです(ただし、流体はしばしば完全に異なるシステムとして実装されます)。

制約解決の基本でさえ、非常に数学を集中させることができ、この主題に関する私の専門知識を超えています。このトピックのより詳細な説明については、Randy Gaulの物理に関する優れた記事シリーズを参照することをお勧めします。


衝突解決の最小数に対処する場合は、おそらく衝突安静の数が多い複雑なセットアップではフレームレートが大幅に低下することを考慮して、可能な限り数を低くする必要性にも対処する必要があります。繰り返しの数について話しているときは、ペアごとの繰り返し数でしたか、それともすべての衝突の繰り返し数でした。
gardian06

1
@ gardian06:それはすぐに書かれた概要であり、かなり拡大できることは確かです。たとえば、オブジェクトのスリープについて言及するのを忘れましたが、これは非常に便利です。反復のために、私はペアのすべてのコレクションを反復し、比較的大きな反復カウント(20+)でさえ、パフォーマンスの問題に気づいたことはありません(しかし、これはオブジェクトがスリープしているため、解決するアクティブな衝突の数が比較的少ない)。
ショーンミドルディッチ

1
素晴らしい答え、+ 1。これを読むと、本当にこれらのアルゴリズムを実装したいと思うようになります。
マイルルーティング

3

一般的な問題:可能なすべてのオブジェクトの組み合わせの中で、非ゼロの交差ボリュームを持つものを判別します。

素朴で一般的なアプローチは簡単です。可能なオブジェクトのペアごとに、交差のボリュームを計算します。これは、O(n ^ 2)の比較的高価な交差演算を必要とするため、通常は実用的ではありません。

そのため、実際の実装は特殊なものであることが多く、交差チェックを回避したり、コストを削減したりできるように、特定の仮定を立てています。空間分割は、オブジェクトが一般に総ボリュームに比べて小さいという事実を利用し、通常、O(n log n)との比較の回数を減らします。軸に沿った境界ボックスと境界球は、オブジェクトが特定のコンパクト性の仮定に従う限り、安価な粗い交差チェックを提供します。等々。


2

私が使用した1つの「衝突エンジン」は、非常に把握しやすいと感じました。

基本的に、APIは、メソッドを有するオブジェクトの種類を提供しcollidesWith、そのような、

  1. そのパラメーターは、衝突の「対象」であるさまざまな種類のオブジェクトでした
  2. 衝突が発生したかどうかに応じてtrueまたはfalseを返しました
  3. オブジェクトのすべての境界長方形が衝突イベントをトリガーするか、これらの長方形内の不透明ピクセルのみを選択するかを選択できるオプションがありました(ピクセルレベルの検出)

私のアプリケーションでは、collidesWith衝突が発生したかどうかを確認するために定期的に呼び出しました。

とても簡単ですね。


想像力を少し伸ばす必要があるのは、衝突するオブジェクトのジオメトリをシミュレートするのにプレーンな境界の長方形では不十分な場合だけだったかもしれません。この場合、1つではなく複数の衝突可能なオブジェクトを使用する必要があります。

一般に、単一の衝突長方形が必要なことを実行できないことがわかった場合、それらを組み合わせたときにこれらの要素が望ましい動作をシミュレート/近似するように、物をより長方形のサブ要素に分解する方法を発明します。

  • エンドユーザーは、背後にあるオブジェクトの数を気にしません。彼らは、最終結果が期待通りに感じる限り、例えば、周りに裏庭のフェンスがある家のように幸せです:

    http://i.stack.imgur.com/4Wn5B.jpg


2

あなたはあなたが話していることについて少し混乱しており、いくつかの異なることについて話していると思います。

このアイテムがロケーションXからロケーションYに移動したと言う機能は、物理学に基づいています(これは、それらがどのように移動し、なぜ移動するかを攻撃します)

衝突の検出に使用される方法は、ゲームの構造に基づいて決定されます。ゲームが大規模なオープンワールドである場合、スペースパーティショニング(クアッドツリー[3Dのオクトツリー]、BSP、従来のグリッド、または昔ながらのすべてをテストするアプローチ)を十分に考慮する必要があります。

衝突検出システムを実装する最良の方法は、段階的に実装することです。

  1. すべてのオブジェクトを一般的な境界ボリューム/形状に配置し、それらをテストします

  2. 1が合格した場合、絶対ジオメトリをテストする準備ができるまで、より複雑なボリューム/形状の繰り返しで繰り返します

  3. ステップ2を繰り返す回数は、形状の複雑さ、およびそれらの形状がどれだけ正確かによって決定される絶対幾何学をテストします。

これらの各ステップは早い段階にあり、進行中の衝突をなくし、実際に触れている場合にのみステップ3でtrueを返すことを目的とする必要があります。

次に、最後の部分は衝突の解決です。これは、衝突を見つけた後に何が起こるかを決定し、それが本当に衝突であることを証明し、それに対して何をすべきかを決定します。これは通常、物理学によって処理されます。

従来のループは次のようになります。

receive input
update physics
collision detection
collision resolution
render
repeat

ゲームエンジンが衝突の絶対ジオメトリをテストすることはほとんどないことを指摘したいと思います。通常、アルゴリズムはアウトラインのステップ2にのみ進みます。
ケビントディスコ

ほとんどのゲームエンジンは、多くの(すべてではない)ケースで絶対ジオメトリをテストします。そうしないと、物理応答に非常に明白な「グリッチ」が発生します。ほとんどのエンジンは、単純な広範なフェーズ(空間分割)、単純な境界ボリュームテスト(最も一般的にはAABB)、そして(必要な場合)単純化されたジオメトリテスト(たとえば、完全なLODレンダリングジオメトリと同じジオメトリではありませんが、レンダリングされたメッシュの低LODバージョンの1つである可能性が高い未加工のジオメトリ)。
ショーンミドルディッチ

@seanmiddleditchは、通常、凹面の多角形/多面体のテストを回避しようとして近似値をテストするという私の意図でした。
gardian06

@ktodiscoそれは、図の凹面、それがどれほど正確である必要があるか、そして物理エンジンに基づいて変化する可能性があるため、物理システムが衝突を解決するために何を返す必要があるかに依存します。応答
-gardian06

@ guardian06 seanmiddleditchの説明ははるかに実行可能ですが、数千のポリゴンで構成されたキャラクター間の絶対的な交差をテストすることはまだ良い考えではありません。
ケビントディスコ

1

グラフィックスカードレベル(通常は三角形を扱う場合)での一般的なアイデアは、何らかの方法でシーンを分割し、N個の三角形すべてをチェックする必要がないようにすることです(これは前処理ステップとして実行できます) )、シーン内のどこにいるかを把握し、そのパーティション内の10〜50個の三角形のみをチェックします。

詳細については、BSPおよびKdツリーを参照してください。他のパーティション分割アプローチもあります。


0

まず、衝突エンジンの最も重要な仕事は、フレームごとに特定の状況で衝突をチェックする必要がないものを判断し、それらのオブジェクトをさらなるチェックから除外することだと思います。

第二に、しかし重要であるが、その最初のステップで選別されなかった残りのオブジェクトに対して、より詳細な(正確な)方法でチェックします。

第三に、最も効率的で適切な方法を使用してチェックを実行します。

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