地形のような立方体を表すBullet Physics CollisionObjectを実装するにはどうすればよいですか?


8

Bullet Physicsライブラリをエンティティ/コンポーネントシステムに正常に統合しました。エンティティは互いに衝突する可能性があります。次に、有限で立方体のような地形と衝突できるようにする必要があります(InfiniMinerまたはそれのクローンMinecraftと考えてください)。昨日、Bullet Physicsライブラリを使い始めたばかりなので、何か明らかなことが足りないのかもしれません。

これまでのところRigidBodycheckCollisionWith(CollisionObject co)関数をオーバーライドするようにクラスを拡張しました。現時点では、他の形状を使用せずに、単なる原点のチェックです。後で繰り返します。現時点では、次のようになっています。

@Override
public boolean checkCollideWith(CollisionObject co) {
    Transform t = new Transform();
    co.getWorldTransform(t);
    if(COLONY.SolidAtPoint(t.origin.x, t.origin.y,t.origin.z)){
        return true;
    }
    return false;
}

これは、衝突がいつ発生したかを検出する限り、うまく機能します。ただし、これは衝突応答を処理しません。デフォルトの衝突応答は、衝突しているオブジェクトを他のシェイプ(おそらくAABB)の外側に移動するようです。

現時点では、地形の形状は世界と同じ大きさの箱にすぎません。つまり、地形と衝突するエンティティは、そのワールドサイズのボックスの外側に向かって発射されます。そのため、衝突応答を変更する必要があるか、地形の形状に直接適合する形状を作成する必要があることは明らかです。では、どのオプションが最適で、どのように実装するのですか?おそらく、私が考えていないオプションがあるのでしょうか?

地形は動的で、プレイヤーによって頻繁に変更されることに注意してください。

回答:


8

私はケビン・リードの答えに感謝しますが、それは私の質問が求めているものよりも高いレベルでした。当然のことながら、Bullet Physicsの知識がなければ、この質問に答えるのは難しいでしょう。私はこれを機能させて、Bullet Physicsに固有の答えを得ました。

RigidBody質問で述べたようにクラスを拡張することに加えて。また、CollisionAlgorithmクラスを拡張する必要がありました。これは主にprocessCollision()関数をオーバーライドすることです。processCollision()(引数として2つの衝突するボディをとる)関数内Transformで、エンティティが現在衝突しているキューブに適切なキューブ形状を作成することができました。次に、エンティティとそれが衝突している特定のキューブに基づいて、デフォルトの衝突が発生するようにします。新しく拡張されたを使用するにはCollisionAlgorithm、処理する形状を処理するアルゴリズムを登録する必要がありました。この場合、それは他のすべてに対する地形タイプです。そのために私は私ので使用registerCollisionCreateFunc()しましたCollisionDispatcher

だから、これから先に続く人たちのために:

  1. 延長RigidBodyして、地形との基本的な衝突チェックを行います。
  2. RigidBodyクラスのインスタンスを作成し、使用しているDynamicsWorldものに追加しますPhysicsProccesor
  3. Extend CollisionAlgorithm、特にprocessCollision()衝突位置と一致するBullet Physicsシェイプとトランスフォームを作成する
  4. を使用CollisionAlgorithmしてのバージョンを登録します。(この登録は、衝突させたい形状のペアごとに1回、複数回行われます。)CollisionDispatcherregisterCollisionCreateFunc()

編集

誰かが興味を持っている場合の動作中のビデオはこちらです。

最初の衝突を検出する

最初の衝突チェックでは、質問で説明しrigidBodycheckCollideWith関数を拡張してオーバーライドします。私の地形には、特定の点で世界がしっかりしているかどうかを確認できる機能があります。基本的に、checkCollideWith関数によって渡されるオブジェクトに対して地形をテストし、そのオブジェクトの境界内のどこかに地形が固体であるかどうかを確認します。

さて、Bulletの次のステップとして、接点を見つけることもあります。これは、上記のprocessCollision()関数で発生します。ここでは、boxShape checkCollideWithをテレインキューブのサイズに設定し、関数で衝突を検出したときに、そのテレインキューブサイズのboxShapeを衝突位置に配置し、Bulletがデフォルトのアルゴリズムをすべて使用して衝突ポイントを検出するようにします。

したがって、基本的に、物理オブジェクトの境界が固体材料に接触する場合。一時的な物理ボディをその場所に配置し、Bulletに、一時的なキューブとの衝突を、常にそこにあるかのようにチェックするように指示します。これは、私の地形のすべての立方体にboxShapeを配置することを非常に最適化するようなものです。何百万ものboxShapesの代わりに、衝突が検出されたときにテレポートする必要があります。


そもそも衝突をどのように検出したかについてさらに詳しく説明していただけますか?
timoxley 2013年

1
@timoxley答えを少し更新しました。
MichaelHouse

次に、複数の点で衝突する単一のアイテム、たとえば、はしごが地面や壁に寄りかかっている場合、どのように処理しますか?
timoxley 2013年

一時的な立方体は、オブジェクトが地形に接触するすべての場所で移動されます。これは、接触点を取得して適切に応答するための細かい検出に使用されます。
MichaelHouse

3

他の回答で実装されている戦略に問題がありました。接触点は時々固執し、立方体以外の形状をすることは一種のハックであり、それは時々オブジェクトが地形をすり抜けることを許しました。

したがって、Bulletクラスのいずれかを変更またはオーバーライドする代わりに、地形を表す組み込みのBullet衝突オブジェクトを使用する代替オプションがあります。BvhTriangleMeshShapeDOCは)三角形メッシュによって表される形状に内蔵されています。

このメッシュは、世界を視覚化するためのメッシュと同時に生成できます。これは、物理オブジェクトがレンダリングされたオブジェクトと正確に一致できることを意味します。

RigidBody地形のチャンクごとにを作成します。そのボディの形状はに設定されていBvhTriangleMeshShapeます。地形が変更されると、チャンクの視覚的表現を再構築すると同時に、物理的形状も再構築します。次に、視覚的形状をバッファリングするときに、物理形状も次のように交換します。

dynamicsWorld.removeRigidBody(chunk.getRigidBody());
chunk.getRigidBody().setCollisionShape(newShape);
dynamicsWorld.addRigidBody(chunk.getRigidBody());

これにより、ボディが適切に取り外され、接点がクリーンアップされます。その後、形状が変更され、再度追加されます。

BvhTriangleMeshShape各チャンクを生成するには、TriangleIndexVertexArraydoc)を維持する必要があります。これは基本的に2バイトのバッファです。1つは三角形の頂点の位置、もう1つはこれらの三角形を作成するためのインデックスです。BvhTriangleMeshShapeはデータのコピーを作成しないため、この頂点配列は維持する必要があります。

ビルトインのBullet物理学クラスをすべて使用すると、私が書くことができるものよりも高速であり、実際に非常に高速に実行されます。この新しい戦略を実行した後、速度が低下することはありません。

ここに画像の説明を入力してください


少なくとも私のテストでは、少なくともチャンクを変換するのにかかる時間と比較して、JBulletがメッシュをクックする(つまり、物理に使用する前にメッシュを前処理する)のが非常に遅いことに注意してください。マーチングキューブを介してメッシュに。私たちは桁違いに遅い話をしています。だから、私はPhysXを調べて、パフォーマンスをどれだけ向上できるかを見ていきます。誰かがこれについての情報を持っているなら、私はそれを聞いてみたいです。
Philip Guin、

2

Bullet Physicsには詳しくありませんが、ODEを使用しました。そこで、「はい」または「いいえ」の衝突テストの後に、一連の接触点を生成するより詳細な形状と形状の衝突テストがあります。

あなたの場合、あなたの世界は箱のコレクションなので、これを行うことができます:

  1. 動く実体のAABBを取ります。
  2. 交差するボリューム内の地形ボクセルを反復します。
  3. 固体の地形のボクセルごとに、一致するボックスを作成し、(できれば物理エンジンの提供されたルーチンを使用して)そのボックスと移動エンティティとの衝突を計算します。
  4. 結果のすべての接触点のコレクションを返します。

これは衝突応答を再定義するものではありません。これはその前のレイヤーです。衝突応答は、衝突から計算された接触点によって完全に決定されます。

私が言ったように、私はBullet Physicsに慣れていないので、そのアーキテクチャがこれに適しているかどうかわかりません。


ありがとう。衝突応答は形状衝突テストにも結びついていると思います。その情報を使用して、それらをどのように離すか、どれだけ遠くまで離すかを決定する必要がありますか?地形の形状に対応していれば、現在の衝突応答で問題ありません。
MichaelHouse

はい; つまり、衝突応答アルゴリズムを再定義するのではなく、そのアルゴリズムへの入力である接触点の生成を再定義します。
ケビンリード
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.