2009年9月23日水曜日

etc - PMDImporterどうなってんのか

今日で休日終了だから、とりあえず解説でも書いておく。

遥か昔、したらばのこのスレ
http://jbbs.livedoor.jp/bbs/read.cgi/music/23040/1236262653/
でBlender用のPMDImpoterを作っている俺じゃない人が居た。


どんだけクソややこしいかについては、その人の書き込み↓を見ればわかる。
たぶんこの人の言うエッジというのは、辺のことではなく、頂点インデックスが3つペアになっている、面を表すものである。

42 :36:2009/03/19(木) 01:56:30 ID:HTvkhXFs0
連投ごめんなさい。

>>39
実は、シェイプキーを含まないマテリアルの判定が、いちばんきついかと。
メッシュの分割点を決める時に、ここ、結構悩みました。
PMDでは、関係するデータがマテリアル、バーテックス(頂点)、エッジ、シェイプキーに分かれて記録されていますが、
エッジ情報から頂点のリストをつくらないと、シェイプキーを含まないマテリアルの判定ができません。

参考:シェイプキーを含むマテリアルを判定する処理する流れの例
1.シェイプキー情報から、シェイプキーで使用する頂点のインデックスのリストを作成(または、表情の種類ごとに分割)
2.マテリアル情報から、各マテリアルが使用するエッジのインデックスの範囲を計算
3.エッジのインデックスの範囲から、各マテリアルが使用する頂点のインデックスのリストを作成(←大きなメモリ消費と重い処理が発生)
4.作成した各マテリアルの頂点リストの中に、シェイプキーの頂点が「全て」含まれるか判定(←これも重い処理)
5.シェイプキーのリストが部分的に含まれる場合は、同一シェイプが分割されないように、マテリアルをまとめる(←これも重い処理。ここで16マテを超えたらアウト)
(3の工程は検索のみで代替もできますが、5で再利用するために作成。)

という事で、シェイプキーの分割判定は、かなり大変です。(実質的に不可能。)

###
そこで考えた別の方法。(現行仕様は、こちら。)
これはメッシュ分割にも関わって来るのですが、「とりあえず登録。あとで移動」する方法です。

PMDでは(メッシュ分割の概念がないので)頂点リストがメッシュごとに分割されていません。(マテリアルごとにも分割されていません。)
なので、Blenderでメッシュを作成する時、第一段階として「全ての頂点」を登録したメッシュを作成しています。(そうしないと頂点のインデックスが変わって、面が貼りづらいので)

参考:処理の流れ(概略(未実装項目を含みます))
1.ボーン登録
2.メッシュ作成(1個だけ)
3.全頂点をメッシュに登録(頂点のインデックスはPMDのインデックスが維持されます)
4.1番目のメッシュのマテリアルを登録(この時点で、マテリアルのインデックスはBlender用のインデックス(0~15)に変換されます)
5.1番目のメッシュのマテリアルに対応した面を貼ります(面はPMDのインデックスを維持)。各面にマテリアルのインデックスを設定します(メッシュごとに0~15。マテリアルのインデックスはPMDと変わります。)
6.メッシュに頂点グループの設定を入れます(骨の影響度の設定)
7.マテリアル数が16を超える場合は、1番目のメッシュ(の頂点、グループなど)をコピーして、2番目以降のメッシュを作成します(メッシュの分割点変更(16マテ毎以外に設定)は未実装。)
(ここまで繰り返し)
8.メッシュの作成が終わったら、全メッシュにシェイプキーを打ちます。(未実装。7と順番を入れ替えるかも)
※シェイプキーは、対応する頂点が存在すれば打てます(最初に全頂点を登録した理由の一つ)
9.各メッシュで、使用していない頂点を削除します(未実装。手動でも(選択方法は少し変わりますが)比較的楽に操作できます。)
→(1)全頂点選択 (2)各マテリアルの頂点の選択を解除 (3)選択されている頂点を削除
→→この時点で、メッシュのマテリアルが使用していない頂点が削除されます(頂点のインデックスが変わる可能性があります)

この方法であれば、比較的楽にシェイプキーが作成出来ると思います。
ただし、メッシュの分割点をまたがる時は、同一シェイプキー(表情)が複数メッシュに分割されます。
(実装予定はありませんが、NLAなどで操作はまとめられるかも。分割点の設定ファイルを読み込む形にした方が無難な気がします。)
スクリプト側で難しい場合でも、手動なら楽な例だったり・・

参考になれば。


で、全然参考にしてないんだけど、要は恐ろしくめんどくさいのである。


次に、俺の実装だが、簡単に書くと

1.全頂点をメッシュに登録(頂点のインデックスはPMDのインデックスが維持されます)
とか簡単にやると、PMDの頂点インデックスが3頂点全部同じ場合失敗するので、なんとかする
(これがモデル製作者のせいということで無視したいところなんだけど、標準で入ってるメイコでもあるんだよな~)
2.マテリアルごとに、次のマテリアルの最初の頂点が、現在のマテリアル範囲の頂点に含まれていた場合、同じメッシュとみなす。(EditモードでCtrl-Lしたみたいなメッシュになる)。ただし、シェイプキーがあるメッシュは、それ用のリストに保持しておいて、無視。
3.メッシュごとに、オブジェクトを作る。最後に、シェイプキーを含むメッシュリストを1オブジェクトにする。


という感じです。

実装の方針としては、できるだけインデックスを使わない実装・・・にしたかったんだけど、結構インデックスだらけに。仕方ないね。

3のシェイプキーを含むメッシュリストが16マテリアル超えてた場合、さらに分割もかけれるけど、16越えないっしょ、たぶん。


あと、まだ微妙におかしいところがあるっぽいので、土曜に直します。

~既知の問題~
・mesh.remDoubles(0.0)
・mesh.recalcNormals()

0 件のコメント: