Model
と ModelInstance
は通常、オブジェクトの視覚的表現のために使用されます。
btCollisionObject
や btRigidBody
は、これらオブジェクトの物理的表現のために使用されます。
ModelInstance
と btRigidBody
の位置を向きを同期させるに、 Bullet では拡張可能な btMotionState
クラスが用意されています。
以下は、こうした同期処理の非常に簡単な例です:
static class MyMotionState extends btMotionState {
Matrix4 transform;
@Override
public void getWorldTransform (Matrix4 worldTrans) {
worldTrans.set(transform);
}
@Override
public void setWorldTransform (Matrix4 worldTrans) {
transform.set(worldTrans);
}
}
上記クラスは以下のように使用することができます:
btRigidBody body; ModelInstance instance; MyMotionState motionState; ... motionState = new MyMotionState(); motionState.transform = instance.transform; body.setMotionState(motionState);
これで、btRigidBody
が動く度に ModelInstance
の位置と向きが更新されます(Bulletによって)。
この方法は ModelInstance
だけに限定されず、Matrix4
を使った変換処理を含んだオブジェクト全て(例えばRenderable
のような)で動作します。
さらに、例えば以下のような簡単なロジックをmotion stateに追加することができます。:
static class PlayerMotionState extends btMotionState { final static Vector3 position = new Vector3(); Player player; @Override public void getWorldTransform (Matrix4 worldTrans) { worldTrans.set(player.transform); } @Override public void setWorldTransform (Matrix4 worldTrans) { player.transform.set(worldTrans); player.transform.getTranslation(position); if (position.y < 0) player.die(); } }
btRigidBody
の変換処理 (位置と回転)は通常、その質量の中心(最も一般的には形状の中心)を起点にして行われるので注意してください。
必要な場合は、btCompoundShape
を使って質量の中心を移動させることができます。
視覚モデルの原点は物理モデルの原点と同じにすることをお勧めします。
これが不可能な場合は、状況に応じてmotion stateのtransformation を変更できます。
Bulletの 変換処理では、translation (位置変更) と rotation (向き変更)のみをサポートしてることを忘れないでください。 scaling(サイズ変更)のような他のtransformation処理はサポートされていません。
MotionState が不要になった場合は、破棄する必要があります: motionState.dispose();
。
Model とはいくつかのプロパティを持った三角形の集まりで、特定の変換処理を伴って描写されます。 物理演算向けではなく画面描写向けに最適化されています。したがってModelは、物理的な形状を効率的に表現するのにはあまり役立ちません。
これがなぜかを理解するには、簡単な箱型のmodelについて考えてみてください。 箱の物理的な形状には8個の角が含まれています。 しかし、視覚modelの場合は24個の角(頂点)が含まれることになります。 これは箱の各面ごとに頂点が設定されるためです。各頂点には面の"法線"情報が含まれます。 でなければ照明のような視覚効果を行えなくなるのです。 そういった理由から、視覚modelは立方体の箱ではなく、6個の独立した四角形で構成されるのです。 これらの四角形 (もしくはそれを構成する三角形)は限りなく薄くなり、体積を持ちません。 そのような物体は、動的物理演算上は不適切な存在なのです。
さらにいくつか問題があります。例えば、大抵の場合modelは物理演算で必要なものよりもさらに詳細な情報を保持しています。 実際にいくつかの形状では、modelの頂点を使う場合よりも簡単な衝突検出アルゴリズムを使うこともできます。 例えば箱型の形状の場合、その形状を構成する12個の三角形に対して衝突検知を行うのではなく、1個の箱に対して衝突検知を行うことが可能です。
これらの問題を解決するためには、プリミティブな形状を使ってmodel に近づける、専用のmodelを使用する、視覚modelと物理形状とで頂点を共有する、といった様々方法があります。 Bullet のマニュアルには、どの方法を選ぶかの助けになる決定表があります。:
静的モデルの場合、 Bullet ラッパーではその衝突形状を作成するための便利なメソッドが用意されています。:
btCollisionShape shape = Bullet.obtainStaticNodeShape(model.nodes);
この場合、衝突形状はそのモデルと同じデータ(頂点)を共有します。
必要に応じて btCompoundShape
を使ってノードの変換処理を行うことができますが、
ノードに対してサイズの変更を適用することはできません。