MMDモデルに物理を適用
このセクションでは、MMDモデルに物理シミュレーションを適用する方法について説明します。
MMDモデルは物理シミュレーションをサポートしており、物理エンジンを使用してモデルのボーンに物理効果を適用できます。
babylon-mmdは、これを実装するための様々なオプションを提供します。各オプションの特性を確認し、使用シナリオに最も適したものを選択できます。
物理エンジンオプション
babylon-mmdは、MMD物理シミュレーションを処理するために3つの物理エンジンをサポートします:
- Bullet Physics:MMDで使用される物理エンジン。Rust wasm-bindgenを使用してWebAssemblyにコンパイルされ、babylon-mmdパッケージに含まれています。
- Ammo.js:Bullet PhysicsのEmscriptenベースのJavaScriptポート。EmscriptenでコンパイルされたWebAssemblyバイナリとして提供されます。
- Havok Physics:Babylon.jsでサポートされる商用物理エンジン。WebAssemblyバイナリとして提供されます。
MMDモデルに適用した場合の各物理エンジンの特性は以下の通りです:
物理エンジン | パフォーマンス | 安定性 | ポータビリティ | 使いやすさ |
---|---|---|---|---|
Bullet Physics | ★★★★☆ - 最適化されたバインディング | ★★★★★ - 優秀なMMD動作再現 | ★★★☆☆ - WebAssemblyをサポートする環境でのみ利用可能 | ★★★☆☆ - APIで開発者エクスペリエンスの配慮が相対的に少ない |
Ammo.js | ★★★☆☆ - 自動生成バインディングによるパフォーマンス低下 | ★★★☆☆ - 良好なMMD動作再現、しかし相対的に高いクラッシュ可能性 | ★★★★★ - asm.jsビルドを使用時、WebAssemblyサポートなしの環境でも使用可能 | ★★★★★ - Babylon.jsとの良好な互換性と利便性 |
Havok Physics | ★★★★★ - 最適化されたバインディング、より高速なエンジンパフォーマンス | ★☆☆☆☆ - 悪いMMD動作再現、深刻な数値不安定性 | ★★★☆☆ - WebAssemblyをサポートする環境でのみ利用可能 | ★★★★★ - Babylon.jsとの良好な互換性と利便性 |
以下、各物理エンジンの初期化方法について説明します。
Bullet Physicsインプリメンテーション
Bullet Physicsエンジンを使用してMMD物理シミュレーションを処理できます。
このBullet Physicsエンジンは、C++からRustへのFFIバインディング後にWebAssemblyにコンパイルされ、babylon-mmdパッケージの一部として含まれています。
Ammo.jsとは完全に独立したバインディングで、優れたパフォーマンスと安定性を提供します。
以下は、Bullet Physicsエンジンを使用してMmdRuntime
を作成するサンプルコードです:
const mmdWasmInstance = await getMmdWasmInstance(new MmdWasmInstanceTypeSPR());
const physicsRuntime = new MultiPhysicsRuntime(mmdWasmInstance);
physicsRuntime.setGravity(new Vector3(0, -9.8 * 10, 0));
physicsRuntime.register(scene);
const mmdRuntime = new MmdRuntime(scene, new MmdBulletPhysics(physicsRuntime));
Bullet Physicsエンジンを使用するには、まずbabylon-mmdが提供するWebAssemblyバイナリをロードする必要があります。これはgetMmdWasmInstance()
ファンクションを使用して行うことができます。
ここで、4つのWebAssemblyインスタンスタイプのうち1つを選択できます:
MmdWasmInstanceTypeSPR
:シングルスレッド、フィジックス、リリースビルドMmdWasmInstanceTypeSPD
:シングルスレッド、フィジックス、デバッグビルドMmdWasmInstanceTypeMPR
:マルチスレッド、フィジックス、リリースビルドMmdWasmInstanceTypeMPD
:マルチスレッド、フィジックス、デバッグビルド
マルチスレッドバージョンは**SharedArrayBuffer
**をサポートする環境でのみ動作します。環境に応じて適切なバイナリを選択してください。
上記の例では、シングルスレッドリリースビルドを使用しています。
const mmdWasmInstance = await getMmdWasmInstance(new MmdWasmInstanceTypeSPR());
MultiPhysicsRuntime
クラスは、Bullet Physicsエンジンを使用して物理シミュレーションを処理するランタイムクラスです。MultiPhysicsRuntime
のインスタンスを作成した後、重力ベクターを設定し、Scene
にアップデートコールバックを登録します。
const physicsRuntime = new MultiPhysicsRuntime(mmdWasmInstance);
physicsRuntime.setGravity(new Vector3(0, -9.8 * 10, 0));
physicsRuntime.register(scene);
MultiPhysicsRuntime
が提供する様々なメソッドを使用して、重力の設定やリジッドボディやコンストレイントの直接追加など、物理シミュレーションを制御できます。詳細については、Bullet Physicsドキュメントを参照してください。
MmdWasmRuntime
を使用している場合は、代わりにMmdWasmPhysics
を使用できます。
これは内部的に同じコードを使用しますが、JavaScriptからWASMへのバインディングレイヤーを排除し、優れたパフォーマンスを提供します。
const mmdRuntime = new MmdWasmRuntime(mmdWasmInstance, scene, new MmdWasmPhysics(scene));
const physicsRuntime = mmdRuntime.physics!.getImpl(MmdWasmPhysicsRuntimeImpl);
// MMD WASMランタイムによって作成された物理ワールドの重力は
// デフォルトで(0, -9.8*10, 0)に設定されるため、このコードは省略可能です
physicsRuntime.setGravity(new Vector3(0, -9.8 * 10, 0));
Ammo.jsインプリメンテーション
Ammo.jsは、EmscriptenでコンパイルされたBullet PhysicsエンジンのJavaScriptポートです。これを使用してMMD物理シミュレーションを処理できます。
以下は、Ammo.jsを使用してMmdRuntime
を作成するサンプルコードです:
import ammo from "babylon-mmd/esm/Runtime/Physics/External/ammo.wasm";
const physicsInstance = await ammo();
const physicsPlugin = new MmdAmmoJSPlugin(true, physicsInstance);
scene.enablePhysics(new Vector3(0, -9.8 * 10, 0), physicsPlugin);
const mmdRuntime = new MmdRuntime(scene, new MmdAmmoPhysics(scene));
babylon-mmdパッケージには、EmscriptenでコンパイルされたBullet Physics 3.25バージョンがammo.wasm
バイナリとして含まれています。これは"babylon-mmd/esm/Runtime/Physics/External/ammo.wasm"
パスからインポートできます。
Ammo.jsは特定のデータに対してコンストレイントの不安定性問題があるため、可能であればBullet Physicsエンジンの使用が推奨されます。
Babylon.js PhysicsPluginV1インターフェースを使用してAmmo.js物理エンジンを管理することもできます。詳細については、Babylon.js Physicsドキュメントを参照してください。
Havok Physicsインプリメンテーション
Havok Physicsエンジンを使用してMMD物理シミュレーションを処理できます。
以下は、Havok Physicsエンジンを使用してMmdRuntime
を作成するサンプルコードです:
import havok from "@babylonjs/havok";
const physicsInstance = await havok();
const physicsPlugin = new HavokPlugin(true, physicsInstance);
scene.enablePhysics(new Vector3(0, -9.8 * 10, 0), havokPlugin);
const mmdRuntime = new MmdRuntime(scene, new MmdPhysics(scene));
Havok Physicsエンジンは良好な数値安定性を持たないため、MMD物理シミュレーションには適さない可能性があります。可能であればBullet Physicsエンジンの使用が推奨されます。
Babylon.js PhysicsPluginV2インターフェースを使用してHavok Physicsエンジンを管理することもできます。詳細については、Babylon.js Physics V2ドキュメントを参照してください。
MMDモデルの物理ビルド
上記の物理エンジンのいずれかでMmdRuntime
インスタンスを作成した後、buildPhysics
オプションをtrue
に設定してMmdModel
インスタンスを作成することで、MMDモデルで物理シミュレーションを有効にできます。
const mmdModel = mmdRuntime.createMmdModel(mmdMesh, {
buildPhysics: true
});
buildPhysics
オプションがtrue
に設定されると、MMDランタイムはPMXファイルで定義された物理データに基づいて、MMDモデルのリジッドボディとコンストレイントを自動的に作成します。
物理ビルドオプション
物理を有効にしてMmdModel
インスタンスを作成する際、物理シミュレーションをカスタマイズするための追加オプションを渡すことができます。
const mmdModel = mmdRuntime.createMmdModel(mmdMesh, {
buildPhysics: {
worldId: undefined,
kinematicSharedWorldIds: [],
disableOffsetForConstraintFrame: false
}
});
利用可能なオプションは以下の通りです:
worldId
:物理シミュレーションのカスタムワールドIDを指定できます。指定されない場合、新しいワールドIDが自動的に割り当てられます。kinematicSharedWorldIds
:キネマティックオブジェクトを共有するワールドIDの配列を指定できます。これは、複数のMMDモデル間でキネマティックオブジェクトを共有したい場合に便利です。disableOffsetForConstraintFrame
:コンストレイントフレームのオフセットを無効にするかどうかを指定できます。モデルのコンストレイントが正しく動作しない場合、このオプションをtrue
に設定してみてください。
マルチワールド物理シミュレーション
まず、worldId
とkinematicSharedWorldIds
オプションは物理シミュレーションワールドを制御します。これらのオプションはBullet Physicsを物理バックエンドとして使用する場合にのみ有効です。babylon-mmdのBullet Physics APIは、複数の物理ワールドを作成し、マルチスレッドで処理し、ワールド間で同期する機能を提供します。
デフォルトでは、MMDモデルが作成されるたびに、各モデルは独自の独立した物理ワールドを取得します。しかし、worldId
オプションを使用して特定のIDを指定すると、そのIDの物理ワールドが既に存在する場合はそのワールドを再利用します。これにより、複数のMMDモデルが同じ物理ワールドを共有できます。
さらに、異なるワールド間でキネマティックオブジェクトを共有したい場合は、kinematicSharedWorldIds
オプションを使用して共有するワールドIDのリストを指定できます。このオプションにより、異なるワールドに属するMMDモデルのキネマティックボディが、それぞれのワールドで相互作用できるようになります。
コンストレイント動作の修正
disableOffsetForConstraintFrame
オプションは、MMDモデルのコンストレイントが正しく動作しない場合に使用されます。デフォルトでは、このオプションはfalse
に設定されています。
MMDはBullet Physics バージョン2.75を使用して物理シミュレーションを処理します。しかし、新しいBullet Physics バージョン3.25では、コンストレイントの動作が変更されており、一部のMMDモデルでコンストレイントが正しく動作しない問題が発生する可能性があります。
このオプションをtrue
に設定すると、コンストレイントソルバーがバージョン2.75と同じ方法で動作し、これらの問題を解決できます。MMDモデルのコンストレイントが期待通りに動作しない場合は、このオプションをtrue
に設定してみてください。
ただし、古いコンストレイントソルバーはより深刻な数値不安定性を持つ傾向があることに注意してください。