Bullet 2.76 Physics SDK マニュアル
4. ライブラリ概要
はじめに
物理エンジンは、衝突判定を行い、衝突や拘束条件を計算し、物体のワールド変換行列(*1)を更新することが主な仕事となります。この章では、剛体ダイナミクスパイプラインの概要と、すべてのコンポーネントで共通の基本データ型、演算ライブラリについて説明します。
(*1)剛体では質量中心、ソフトボディでは各頂点
ソフトウェア設計
Bulletはカスタマイズ可能な形で設計されており、また各機能がモジュール化されています。
そのため、以下のような使い方も可能です。
- 衝突判定コンポーネントのみ使用
- ソフトボディ力学コンポーネントを使用せず、剛体力学コンポーネントのみ使用
- ライブラリのごく一部のみ使用し、ライブラリを拡張する
- 単精度/倍精度を選択して使用する
- 独自のメモリアロケータを使用し、独自のパフォーマンス分析やデバッグ描画を構築する
主要なコンポーネントの構成は以下の通りです。
[図]
剛体力学パイプライン
細かい話は後にして、まず下の図を見てください。これは、Bullet physicsパイプラインにおいて最も重要なデータ構造と演算処理ステージを表しています。このパイプラインは左から右に実行されます。重力の適用に始まり、最終位置の決定、ワールド変換行列の更新までの流れが記載されています。
[図]
このパイプラインおよびデータ構造全体はBulletの力学ワールドを現しています。'stepSimulation'が呼ばれると、上記すべてのステージが実行されます。デフォルトの力学ワールドとして、btDiscreteDynamicsWorld が提供されています。
Bulletは利用者が力学ワールドの部分部分を選択できるようにしています。例えば ブロードフェーズ衝突判定、ナローフェーズ衝突判定(ディスパッチャ)、拘束条件ソルバなどです。
統合について
Bulletを自身の3Dアプリケーションに使用する場合、まずHellowWorldデモを理解するのが一番の近道です。このデモは Bullet/Demos/HelloWorld に置いてあります。端的に言うと、このデモは以下のような処理を行います。
- btDiscreteDynamicsWorld もしくは btSoftRigidDynamicsWorldを生成
これらは btDynamicsWorldの派生クラスで、物理オブジェクトや拘束条件を管理する高水準のインターフェースを提供します。毎フレームのオブジェクト更新も実装されています。
- btRigidBodyを生成し、btDynamicsWorldへ追加
btRigidBody もしくは btCollisionObjectを生成するには、以下の値を指定する必要があります。
- 質量:動的力学オブジェクトに対しては正の値、静的オブジェクトには0を与えます。
- 衝突形状:長方形、球、円錐、凸形、凹形、三角メッシュなど。
- 摩擦係数や反発係数といった物質の性質
フレーム毎の更新は、下記メソッドで実施します。
- stepSimulation
stepSimulationを呼び出すと、btDiscreteDynamicsWorldはごく短いタイムステップでシミュレーションを行うのではなく、その間を補間することにより、タイムステップ変数を考慮しつつ自動的に実行します。内部の固定タイムステップは60Hzです。stepSimulationは衝突判定、物理シミュレーションを処理します。stepSimulationはbtmotionStateのsetWorldTransformを呼び、有効なオブジェクトに対してワールド変換行列を更新します。
次章では、衝突判定および剛体力学についてより詳しく説明を行います。Bullet/Demosにデモがありますので、実際の詳細な内容はこちらをご覧ください。もし分からない機能がありましたら、Bulletサイト(http://bulletphysics.org)のphysicsフォーラムをご覧ください。
基本データ型と演算ライブラリ
基本データ型、およびメモリ管理やコンテナはBullet/src/LinearMathにあります。
- btScalar
btScalarは気取った名前がついていますが、実体は浮動小数点です。単精度/倍精度浮動小数点でライブラリをコンパイルできるようにするために、ライブラリ全体でbtScalarというデータ型を使うことにしています。デフォルトでは、btScalar は float型に定義されています。ビルドシステムもしくはBullet/src/LinearMath/btScalara.hにてBT_USE_DOUBLE_PRECISIONを定義することにより、doubleとして使用することができます。
- btVector3
3D位置およびベクトルを表します。btVector3はX,Y,Zの3つの値を持っています。ただし、SIMDへの互換を保つために、4番目に未使用のW要素を持っています。加減算やベクトルの長さ取得など、多くの操作がbtVector3で実装されています。
- btQuaternion と btMatrix3x3
3Dの向きや回転は、この btQuaternion、btMatrix3x3を使って表すことができます。
- btTransform
btTransformは、位置と向きを組み合わせたものです。位置やベクトルに対して、ある座標空間から別の座標空間への変換をする場合に使用されます。スケーリング(拡大縮小)や変形はできません。
なお、Bulletは右手座標系です。
[図]
btTransformUtil, btAabbUtil はそれぞれ変換、AABBの共通のユーティリティを提供します。
メモリ管理、配置、コンテナ
SIMDやDMAをCell SPUへ変換する場合、16byteの配置は非常に重要です。Bulletはこの配置を管理するデフォルトメモリアロケータを提供しています。また独自のメモリアロケータを使用することも可能です。Bulletでは、すべてのメモリ配置に下記クラスを使用します。
- btAlignedAlloc : 指定サイズでメモリを取得します
- btAlignedFree : btAlignedAllocで取得したメモリを解放します。
デフォルトのメモリアロケータをオーバーライドする場合、以下の中から選択することができます。
- btAlignedAllocSetCustom は独自のカスタムアロケータがメモリアラインメントをサポートしないときに使用します。
- btAlignedAllocSetCustomAligned は独自のカスタムアロケータがメモリアラインメントをサポートするときに使用します。
以下のマクロを使用すると、構造体やクラスが自動的にアラインメントされることを保証することができます。
- ATTRIBUTE_ALIGNED16(type) variablename は16byteの変数を生成します。
オブジェクトを配列で管理する必要性がでてくる場合があります。元々Bulletライブラリは配列にはSTL std::vectorを使用していましたが、移植性、互換性を保持するために配列クラスを定義しなおしました。
- btAlignedObjectArray はstd::vectorとほとんど同じものです。アラインメントが保証されています。配列をクイックソート/ヒープソートするメソッドを持っています。
Microsoft Visual Studioデバッガが btAlignedObjectArrayやbtVector3の内容を表示できるようにするためには、Bullet/msvc/autoexp_ext.txtの説明に従って設定してください。
[図]
時間計測とパフォーマンス管理
パフォーマンスのボトルネックを特定するために、Bulletは階層的なパフォーマンス測定マクロを使用しています。
- btClock はマイクロ秒の精度で時間を計測します。
- BT_PROFILE(section_name) はセクションの分析を開始します。
- CProfileManager::dumpAll(); 階層的なパフォーマンスのダンプをコンソールに出力します。シミュレーションを実行した後に呼び出します。
- CProfileIteratorは分析ツリーを巡ることができるクラスです。
この分析機能は Bullet/src/LinearMath/btQuickProf.h で #define BT_NO_PROFILE 1 を定義することにより機能をOFFすることができます。
デバッグ用描画
シミュレーションデータ構造を視覚的にデバッグできると、非常に効率的です。例えば、物理シミュレーションデータがグラフィックデータと一致しているかどうかを確認することができます。またスケーリングの問題、拘束条件の設定ミスなどを特定することができる場合もあります。
btIDebugDraw はデバッグ描画用のインターフェースクラスです。この派生クラスで仮想メソッド'drawLine'などを実装してください。
独自のデバッグ描画をsetDebugDrawerメソッドで力学ワールドに登録してください。
dynamicsWorld->getDebugDrawer()->setDebugMode(debugMode);
毎フレームごとに以下のようにデバッグ描画メソッドを呼びます。
world->debugDrawWorld();(*2)
デバッグには、下記のようなモードがあります。
- btIDebugDraw::DBG_DrawWireframe
- btIDebugDraw::DBG_DrawAabb
- btIDebugDraw::DBG_DrawConstraints
- btIDebugDraw::DBG_DrawConstraintLimits
デフォルトでは、デバッグモードで設定したすべてのオブジェクトが描画され、多くのオブジェクトがある場合はディスプレイには無茶苦茶な画面が表示される場合があります。そこで、以下のように特定のオブジェクトをデバッグ描画させないようにすることができます。
int f = objects->getCollisionFlags();
ob->setCollisionFlags(f|btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT);
*2)この機能は btCollisionWorld および btDiscreteDynamicsWorld でサポートされます