Systems
WMMDのアーキテクチャ:ホストできるMMDランタイム
同じコードがエディタにもARホストにもオフラインレンダラーにもなるよう、Rustのクレートを厳格な依存規則で階層化しています。
WMMDは、Rustで書いているMikuMikuDanceランタイム兼レンダリングバックエンドです。
設計上の制約は「ホストできる」という一語に尽きます。いまはデスクトップエディタを動かしています。でも同じコードベースを、VJツール、AR/VRランタイム、ゲームエンジン、モーションキャプチャのパイプライン、オフラインレンダラーに組み込みたいと思っています。
そのためには、どの層も「ウィンドウ・GPU・時計は自分のものだ」と暗黙に仮定していないことが条件になります。言うのは簡単です。そして、たいてい別の何かを直している最中に、うっかり破られます。
階層構造
ワークスペースは、依存が一方向にだけ向くように並べたクレート群です。
wmmd-clock- トランスポート用の時計。外部依存はゼロ。wmmd-runtime- CPUのみのシミュレーションエンジン。シーンデータ、スケルトン、物理バックエンド、IKソルバー、フレーム更新ループ。wmmd-asset- PMX/PMDの解析、VMDアニメーションの読み込み、テクスチャ解析、パス解決。マテリアル処理はwmmd-materialに委譲します。wmmd-render- バックエンド非依存のレンダリングインターフェース。依存はglamとserdeだけです。wmmd-render-wgpu- そのインターフェースのwgpu実装。GPUパスをすべて所有します。wmmd-host-winit- デスクトップのサーフェス。それ以上のことはしません。wmmd-session、wmmd-ui-egui、wmmd-audio、wmmd-export、wmmd-editor、wmmd-desktop、wmmd-tools- ホスト中立のセッション状態、パネル、オーディオ、オフライン書き出し、そしてその上のアプリケーション。
不変条件こそがアーキテクチャ
依存グラフは明文化された不変条件のリストで守っています。違反はスタイルの問題ではなく、バグです。
全体を形づくる主なものはこれです。
wmmd-renderはGPU依存もランタイム依存もゼロ。CameraUniformのようなGPUレイアウト型はwgpuクレートに置きます。抽象インターフェースがランタイムのコマンドを参照することはありません。wmmd-runtimeはファイルを読み込まない。 ホストがアセットクレートを呼び、解析済みのアセットを持つAddModelコマンドを積みます。エンジンはファイルシステムについて何の意見も持ちません。wmmd-render-wgpuはスワップチェーンを所有しない。 ホストがフレームを取得し、レンダーターゲットを作り、render()を呼び、提示します。この1つの規則があるからこそ、ARやヘッドレスのホストが成立します。wmmd-render-wgpuはegui非依存であり、wmmd-host-winitはサーフェス専用です。GPUコンテキストはレンダークレート側にあるので、winitに依存しないホストでもデバイスを作れます。RenderRequestが唯一のインターフェース点。 呼び出し側がカメラ、シャドウ中心、ライティング、デバッグフラグ、フレームを組み立てて渡します。wmmd-clockとwmmd-audioは独立。 どちらもシーンやレンダリングを知りません。ホストがランタイムへ配線します。
なぜここまでやるのか
これらの規則はどれも、デスクトップ専用エンジンなら楽だったはずの近道を自分で断ったものです。レンダラーにスワップチェーンを持たせるのは1行で済みますし、今日の作業はそのぶん確実に減ります。
見返りが来るのは後です。新しいサーフェス、たとえばVision Proホスト、VJプラグイン、書き出しジョブを足すとき、レンダラーをフォークするのではなく、すでにあるインターフェースを駆動するだけで済みます。
エンジンがモデル非依存なのも同じ種類の規則です。修正は必ずシステムのレベルで行い、特定のMMDモデルで分岐しません。1つのファイルで再現したバグなら、その修正は妥当なPMX/VMD入力の空間全体に効かないといけません。