Godot モデル動的構築 自分の事例1
GodotエンジンではUnityやUE同様、インポートした3Dモデルは、エディタのGUI上でセットアップします。インポート設定を変更して、マテリアルを変えたりして、場合によってはスクリプトをアタッチして、パラメータを設定したりして、シーンとして保存します。
でもね、このワークフロー、個人的に、わがままだけど、回避したいんです。
BlenderでCtrl+S押して、ファイル名とオブジェクト名をスクリプトにちょろちょろっと書いたら、それで動いてほしいんですよ。インポート設定もデフォルト設定のまま。それはトライ&エラーのしやすさにつながるし、気持ちもすごく軽くなるんですよ。
あとなんのかんの、エンジンのエディタで作るエンジン専用のデータって、あまり入れたくないんですよ。フットワーク的に。
極端な話、プロジェクトが壊れたりしてゼロからプロジェクト作る羽目になっても、インポートファイルを片っ端からドラッグ&ドロップして、デフォルト設定のままインポートさせて、スクリプトをコピペすれば、10分で元に戻る。そのくらいであってほしいんです。
筆者は前作をUnityで作るときは、Prefab作るのを避けたくて避けたくて、エディタスクリプトの機能で自動でPrefabやマテリアルやアニメーション遷移定義(Controller)を作るようにしました。制作が長引いてマイグレーション繰り返したこともあって、Unityプロジェクトがボロボロになっていたのですが、これのおかげで無事再生できました。他機種への移植のときもクリーンな環境でスタートできました。
だからね。やっぱ要るんです、自分には。セットアップせずに使う仕組み。Godotエンジンでも。できれば今度はエディタ上の事前処理さえも無くしたい。「Prefab作れボタン」を押さなくていいようにしたい。
大観
というわけで自分は3Dモデルのノード構築システムをこう作りました。今作ってるゲームではこれを使ってます。
一番下のMiniatureが肝となるクラスです。なのでこのモデル構築機構全体を指して『Miniatureシステム』って呼んでます。けれんみあったほうがテンション上がるよね。タクティクスオウガの『HERMITエンジン』とかさ。
Miniature
MeshInstance3Dを組み合わせて、見た目ノードを構築します。これ自体をMeshInstance3Dにアタッチすることもできます。(単純なモデルは単一ノードで済むようにしたい。)
マテリアル、シェーダ、テクスチャ、シェーダパラメータを変えることができます。マテリアルは同メッシュで共有することも、ノードごとにコピーを持つこともできます。
ミニチュアの名前通り、静物でもあり生物でもあります。
炎ビルボードのようなVFX含め、3Dの見た目ノードはほぼすべてこれを使います。動的に生成したメッシュを使う場合などは例外です。
Doll
Miniatureの派生クラスで、Skeleton3Dを伴うモデルです。要するにキャラクター用です。
AnimationPlayerも保持しています。ただ、AnimationPlayerの実際の制御は放棄しています。再生時間を安全に取得するなどの便利系関数くらいは用意しています。が基本的には、継承先の親クラスや他の利用クラスに、AnimationPlayerの参照を取得させて勝手に使わせます。
また、ボーンに対するノードのアタッチや、ボーンの現在位置の取得を提供します。物を持たせたり、眼が光ったりするのに使います。
名前の通り「人形」です。自分からは動かない。
後述の継承クラスPuppetが思想が強すぎるので、ローレベルなスキンメッシュクラスをMiniatureとの間に挟んだ感じです。
例えば
・動物の群れが敵に襲い掛かる魔法技のVFX
・髪型変更画面でのプレビュー
・レースゲーでコース外にいる観客
こういったワンショットのキャラクター表現での使用を想定してます。
Puppet
Dollの派生クラスで、アニメーションの再生を管理します。
役割は3つあって、1つはAnimationPlayerのラッパであること。AnimationPlayerは自由度が高すぎて自分には制御しきれないので、AnimationPlayerの使い方を制限したうえで、必要な機能だけをPuppet側で実現することにしました。「文脈」を意識せずとも正常に使えるようにしてます。
2つ目の役割は、タイミングの通知です。特定アニメーションが特定時間に達したときに、事前に設定されたフラグを通知してくれます。
足音とか、VFXとか、攻撃ヒットタイミングとか、そういうのに使います。
3つ目の役割は、Intenst(意図)引きのアニメーション名定義データでも動かせる機能を提供することです。
「剣で斬る」Intentで再生を支持されたときに、ヒューマンなら"SlashWithSword"、ゾンビなら"Swing1HandedWeapon"(片手武器なら共通動作)、ドラゴンなら"Attack"(やけっぱち)を再生します。この定義データはツリー状で、根元に向かってフォールバック先が用意されていて、とりあえずどんなIntentでも動いてくれます。無茶ぶりOK。
ファンタジーRPGだと必須な機能なので。
Workshop
モデルファイルの分解場であり、分解したデータの置き場です。GodotのAutoLoad機能によってシングルトンとして常に存在します。
Miniature派生クラスから、「このファイルのこの部分が欲しい」とリクエストがあったら、blendファイルやglTFファイルをロードします。ロードした3Dモデルはシーンリソースになるので、これをバチバチと分解します。分解したものはキャッシュしておきます。リクエスト通りにデータを返します。
データの対象
次の4つ
Bough。大枝。こんな概念は一般的じゃないので、勝手に名前つけました。複数のNode3DとMeshInstance3Dからなるツリー状の塊。直感的にはモデルのパーツ。
アーマチュア。Skeleton3Dノードとその親ノード。2ノード。
これも勝手に名前を付けた概念です。AnimationLibraryリソース。インポート時に生成されている。
バリエーション用テクスチャ。このモデル用の「替え」テクスチャを、特別に保持しておく。
Boughは上の図のような感じです。後の記事で何度も出てきます。
Paintbox
モデルインポート時にGodotがデフォルトで生成するマテリアルに代わる、ゲーム用のマテリアルを生成します。
既存マテリアルのパラメータやシェーダーの変更もします。
各クラスの詳細は・・・
つづく
この記事が気に入ったらサポートをしてみませんか?