応用編1: モデル(PMX)のロードと表示

応用編1: モデル(PMX)のロードと表示

1. モデル(PMX)のロードと表示

本章のゴール

babylon-mmdの基本的なローダーをセットアップし、3D空間にキャラクターを表示させる方法を習得する。

ここから始まる応用編では、いよいよ「babylon-mmd」を用いて解説を進めます。

読み進める前に

本チュートリアルではコードの要点を抜粋しながら仕組みを解説していきます。babylon-mmdの開発者が公開している 公式テンプレートsrc/SceneBuilder.ts に実際の構成がまとまっているので、手元に開きながら読み進めると各ステップの位置づけが掴みやすくなるはずです。

モデルの導入

MMDのキャラクターを形作る基本となるのが、モデルデータ(PMXファイル等)です。このデータには、メッシュやボーン、質感(マテリアル)の設定など、キャラクターを表現するあらゆる情報が含まれています。

しかし、Babylon.jsは標準の状態ではこの特有の形式を読み込むことができません。表示に至るまでにはいくつかの準備ステップを踏む必要があります。

読み込みステップ

モデルを読み込んで表示するまでには、大きく分けて5つのステップを踏む必要があります。「Babylon.jsの標準機能」と「babylon-mmd固有の機能」がどのように連携していくのか、実際の流れに沿って確認していきましょう。

  • ステップ1: 拡張ローダーの組み込みとマテリアル変換機の準備
  • ステップ2: データのダウンロードと解析
  • ステップ3: シーンへの実体化(画面への表示)
  • ステップ4: 座標の確定と影の設定
  • ステップ5: MMDランタイムへの登録と物理演算の構築

1. 拡張ローダーの組み込みとマテリアル変換機の準備

まずPMX形式を解析するためのbabylon-mmdの拡張機能をインポートし、Babylon.jsの背後で待機させます。さらに、PMX特有の複雑な質感(トゥーンシェーディングやスフィアマップなど)を、Babylon.jsの空間上で正確に再現するための専用翻訳機である MmdStandardMaterialBuilder のインスタンス(materialBuilder)を作成し、手元に準備しておきます。

import "babylon-mmd/esm/Loader/pmxLoader";
import { MmdStandardMaterialBuilder } from "babylon-mmd/esm/Loader/mmdStandardMaterialBuilder";

const materialBuilder = new MmdStandardMaterialBuilder();

2. データのダウンロードと解析

LoadAssetContainerAsync は、指定されたURLからファイルを非同期でダウンロードするBabylon.jsの標準機能です。ここでBabylon.jsが「.pmx」という拡張子を検知すると、ステップ1で待機させておいたbabylon-mmdのプラグインが自動的に介入します。PMXのバイナリデータを解読し、頂点情報やボーンをBabylon.jsのメッシュやスケルトンへと変換します。同時に pluginOptions という設定枠を通じて materialBuilder を読み込み処理に引き渡すことで、モデルの解読と同時に「トゥーンシェーダー」等の専用マテリアルへの変換も自動的に行えます。この時点ではデータはコンテナの中に格納されているだけで、まだ画面には表示されていません。

import { LoadAssetContainerAsync } from "@babylonjs/core/Loading/sceneLoader";

// [Babylon.js] 標準の非同期アセット読み込み関数
const container = await LoadAssetContainerAsync(modelItem.fileUrl, scene, {
    pluginOptions: {
        mmdmodel: {
            loggingEnabled: false,
            materialBuilder: materialBuilder
        }
    }
});

3. シーンへの実体化(画面への表示)

container.addAllToScene() は、コンテナ内に準備されていたメッシュやマテリアルを一斉に現在のシーン(3D空間)へ展開するBabylon.jsの標準メソッドです。このメソッドが呼ばれた瞬間、ブラウザの画面上にキャラクターの姿が描画・表示されます。また、後続のプログラム操作のために、展開されたモデル群の元締めとなる親ノード(rootNodes[0])を変数として取得しておきます。

import { TransformNode } from "@babylonjs/core/Meshes/transformNode";

// [Babylon.js] コンテナ内の全要素を現在のシーンに追加
container.addAllToScene();

const rootMesh = container.rootNodes[0] as TransformNode;

4. 座標の確定と影の設定

配置されたルートメッシュに対して、立ち位置(position)などを設定します。ここで重要なのが、Babylon.jsの標準メソッドである computeWorldMatrix(true) です。ボーンやメッシュが入れ子構造になっているキャラクターの各座標を、「空間全体の絶対座標(ワールド座標)」として即座に強制再計算させます。これにより、この後の物理演算を適用する際の位置ズレを防ぎます。合わせて、モデルの各メッシュに対して「他のオブジェクトが落とした影を受け取る(receiveShadows)」設定などを付与します。

import { Vector3 } from "@babylonjs/core/Maths/math.vector";

rootMesh.position = new Vector3(0, 0, 0);
rootMesh.computeWorldMatrix(true);
if (rootMesh.metadata?.meshes) {
    rootMesh.metadata.meshes.forEach((m: any) => {
        m.receiveShadows = true;
    });
}

5. MMDランタイムへの登録と物理演算の構築

最後に、配置したメッシュをただの3Dオブジェクトから「MMDキャラクター」としてシステムに認識させます。ここからは完全にbabylon-mmd固有の処理領域となります。createMmdModel() を通すことで、「このモデルは後でVMDモーションで動かす」「表情モーフを使う」といった情報をランタイムに登録します。さらに buildPhysics を指定することで、PMXデータ内部に含まれる「剛体」や「ジョイント」の情報を読み取り、babylon-mmdの物理空間(Bullet Physics等)へモデルを構築します。この際、kinematicSharedWorldIds を指定することで、指定したワールドとキネマティック剛体の情報を共有することができます。

import { MmdStandardMaterialProxy } from "babylon-mmd/esm/Runtime/mmdStandardMaterialProxy";

const mmdModel = currentMmdRuntime.createMmdModel(rootMesh, {
    materialProxyConstructor: MmdStandardMaterialProxy,
    buildPhysics: { kinematicSharedWorldIds: [0] }
});

モデル生成時のオプションとして上記のように materialProxyConstructor: MmdStandardMaterialProxy を指定します。

このプロキシオブジェクトを組み込むことで、MMDのモーションデータが要求する複雑なマテリアルの色変化を、Babylon.jsの描画エンジンへと正しく伝達し、自然な表情や演出を再現できるようになります。


お疲れ様でした。これでキャラクターを3D空間に立たせ、物理演算を含めた完全な状態で表示させることができました。