名前解決機構を考案し、シェイプ、コンストレイント、モデル結合が Collada ファイルを読み込んだ時点で行えるようになりました。
今回は同じく名前解決を使いますが、スキンメッシュのフレーム(骨)と別のオブジェクトを置換することを目的とします。
何の意味が?という疑問もありますが、まぁ単純に研究からはすこし外れて、面白そうだからやってみたいと思います。
遊びながら研究を進められるのが趣味の良いところです。
これまでの物理オブジェクト作成機構を残したまま、新たに機構を入れます。
まずは現在の機能を確認してみましょう。
Blender でこのようなボーンとスキンメッシュを用意すると…
このように読み込んだ時点で、ボーンに物理オブジェクトが作成され、継ぎ目にコンストレイントが作られます。
これを物理演算させると、スキンメッシュアニメーションを確認することができます。
詳細は1年10ヶ月前の068話と069話に記録しています。
さて、デバッグしながら少しずつ機能を入れていきます。
まずは適当な位置に関係ないオブジェクトを配置します。名前を Cube.001 としました。
そして数あるフレームの一つを Bone-Cube.001-Bone.000 とリネームします。
名前規則を設けて、この場合は Bone のオブジェクトを作成せずに、Cube.001 とするという処理を入れてみます。
あれ?オブジェクトが移動するとスキンメッシュが動くのはどういう関連付けで行っているのでしたっけ?
しまったな、よくわからない。
コードを見た感じ、Resource の nodeInfo の MeshJointIndex, TypeInfoIndex の付替えを行なうとうまくいきそうではあるのですが…
試してみます。
そのためにはまずノード名からノードインデックスへのマップが必要で、これを最初に作成します。
その後、ノードを再帰的に見ていき、MeshJointIndex と TypeInfoIndex を交換します。
デバッグ中ですが結果です。(どういうこと?)
ボーンオブジェクトとコンストレイントは作られなくなり、関係ないオブジェクトが作られました。
しかし、描画されるスキンメッシュが2つになり、親ノードしかフレームの姿勢変更が反映されない。
うーん、MeshJointIndex をキーワードにコードを見ると、どうもノードの Type も交換しないといけない様子。
うまくいきました。
リロードすると関係が壊れてしまったので、リロード処理を見直します。
なるほど、読み込み時の交換処理がリロードでも行われ、交換の繰り返しによりおかしくなっていました。
名前解決はするが、交換済みならば何もしないという処理を設けてリロード結果も意図したものとなりました。
これですべての名前解決が揃いました。
遊んでみましょう!
最初に思いついたのが、ラグドールです。
魂の抜けた人形の振る舞いをする関節構造を Blender 側で試行錯誤しながら用意し
そのオブジェクトとボーンを交換してなんでも良いのでモデルを動かしてみようと思います。
<ここからしばらく Blender 側で作業>
下半身に ArmatureForAlice を配置します。
試しに「右ガン」を RGun にリネームし、Editモードで[P]を押すことでSeparateメニューが表示されるので
Selected を選びます。
同じようなことを ムチ にも行ってみます。
ひとまずこの状態で Kimberlite2 で読み込むと次の状態になります。
これは既存の名前解決を利用しない場合の状態です。
オブジェクトにフィットするように衝突形状を用意し、そのオブジェクトと同じ姿勢のボーンを作り
そのボーンのスキンメッシュとしてオブジェクトを用意したらどうでしょうか?
試験的に RGun だけ名前解決してみます。結果は…?
Compound はうまくいきましたが、スキンの設定がうまくいきません。
実装でちゃんと交換できているか見てみます。
交換できています。
では、スキンの設定がおかしい?
ボーンと同じ名前の頂点グループにしないといけないっぽい。
置換先オブジェクトに追従してくれるようにはなった。
まだ問題が残っている、このオフセットのずれをどうにかしないといけない。
マニュアルを073話で作っているので参照します。
チュートリアル6にスキンメッシュについて記載されていました。
ここには特に記載なし。
ソースを読んでどこを直すべきか考え、試し、なんとか意図した動作になるように修正できました。
Collada の controller ノードには BindShapeMatrix という行列があるのですが
これはボーンとメッシュをバインドした時にメッシュオブジェクトがどんな姿勢だったかというものです。
ボーンがどの姿勢であったかは関係ない情報で、メッシュオブジェクトがどこにいるかで決まります。
で、この BindShapeMatrix の値は描画の時にどこにも考慮されていませんでした。
そこで、ボーン一つ一つのバインド逆行列というものに、この BindShapeMatrix を掛けるように修正し
バインド時にオブジェクトが任意の姿勢であっても、正しくスキンメッシュアニメができることを確認しました。
では、バグを直したところでもう一度 RGun でチェックします。
まだズレていますね。
あとは何でしょう?
ボーンの位置と対象メッシュの位置がずれている、これですかね?
うまくは行かないまでも、結果には影響があるはず。
やはり、そして変更すべきは、ボーンの位置ではなく、メッシュの基点か?
全部の基点を合わせた、これでどうなる?
これ、どっかで見たな。(振り出しに戻る)
まるでボーンの中心が、置換対象オブジェクトの基点に移動するかのようなズレ…もしやコード側でそのような対応を入れている?
調査します。
この読みは正しい、ボーンの位置はボーンの始点ではなく、始点と終点の間の位置でした…
では、どうすれば?
ボーンのバウンディングボックス中心を置換対象のオブジェクトのバウンディングボックス中心の基点に合わせるという
Blender 側の調整で対応することにしました。
その結果がこちら↓
やりましたね。回り道しましたが、まぁテストの手間が省けたということで…
同じ要領で残りのオブジェクトも対応してみましょう。
Blender の使い方の話ですが、頂点ウェイトペイントで対象メッシュ全体を赤く塗りたい場合があります。
実は頂点ウェイトペイントモードには塗りつぶし機能はありません。
ではどうやって解決するのかというと、オブジェクトの頂点グループにて
Edit モードで対象頂点を全て選択し、Assign します。これで解決できました。(わかりづらい)
残るは鞭、これが 25 個もオブジェクトがあって大変なんです。
コンストレイント作成にてバグがあったので修正しました。25個のオブジェクトを名前解決で繋いだ結果がコチラ↓
物理オブジェクトとコンストレイントを表示させると次の結果になります。
ConeTwist コンストレイントで繋げました。コンストレイントを調整することでより鞭らしくなります。
あとは本体をラグドールに出来るか作業します。
何かバグがあればここに書きます。
さっそくバグ発見、例えば RGun, LGun それぞれを単品で Collada に書き出す場合は問題は起こりません。
しかし、両方を Collada に書き出して読み込もうとするとクラッシュしました。
ほかにも、アリスと共に読み込むとクラッシュはしないものの
自動作成されたシェーダコードはスキンメッシュではなく単なるメッシュに…
原因は何か?それはマテリアルの重複です。
現在オブジェクトを一つの状態から、Edit モードで分割 [P] キーを使いました。
これによりマテリアルがオブジェクトごとにリンクしています。
下図の赤枠に 4 個のオブジェクトで共有していることを示しています。
ということで独立したインスタンスに変えます。
先ほどの赤枠のボタンを押すと、別名を付けて新規マテリアルとして用意されます。
これで正しく動作するはずです。確認してみます。
うまくいきました…が、オブジェクトが重なってしまっています。
物理オブジェクトはそれぞれ正しく設定できているので、付随するモデルの描画コードを確認します。
問題は変換時のメッシュジョイント情報へのインデックスマップの作成部分にあり
簡単に言えば、過去に構築したジョイントリストと一致したらそれを利用する…という処理の所
その過去情報を構築していなかったため、常に不一致を返していた。
さらに、値格納時にその過去情報を参照していたがため、常に値は0を利用、そのためモデルが重なって表示されていました。
修正後は正しくスキンメッシュ描画が行えているようです。
この状態で、鞭と一緒に描画してみます。
こちらが物理オブジェクトの描画結果
次に付随モデルの描画結果を示します。
正しく描画できている様子です。
ちょっとデバッグに時間を使ってしまって、まだ本体の方まで手を入れていません。
まだまだバグに遭遇しそうなので、ひと通りラグドールを完成させる操作までは確認したいと思います。
次回をお楽しみに!
2014/09/13 初記。
2014/09/15 更新。