衝突エンジンと物理エンジンには大きな違いがあります。物理エンジンは一般に衝突エンジンに依存していますが、それらは同じことを行いません。
衝突エンジンは、衝突検出と衝突応答の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の物理に関する優れた記事シリーズを参照することをお勧めします。