チュートリアル / 読んで触ってよくわかる!Mayaを使いこなす為のAtoZ
第110回:スキニング後に頂点が増減する編集をした時の対処編
- Maya
- キャラクター・リグ
- ゲーム
- コラム
- チュートリアル
- モデリング
- 初心者・学生
前回に引き続きこの話題で。
映像制作でもゲーム制作でも、モデリングの作業履歴を定期的に削除して、データをきれいにすると作業効率が良くなります。
特にゲーム制作ではFBXなどに書き出すなど、データがきれいでないとゲームに悪影響が出ることもあり、注意深くクリーンナップする必要があります。
「デフォーマ以外のヒストリ」で不要な作業履歴を削除すればいいはず!
ところが、エラーが出て思ったようにいかない…。よくあります。
というわけで、スキニング後にメッシュを編集したら、どのようにして作業履歴をきれいさっぱり取り除くか見ていきましょう。
メッシュの編集では多くの場合でコンポーネントが増減します。状況によっては簡単に直せたり、ちょっと手間がかかったりします。
毎回手探りで操作しがちなのですが、よくよく考えてみれば大きく2つのパターンにまとまります。
それぞれを「簡単コース」「しっかりコース」として、どちらで対応すればよいかご紹介します。
スキニング後に頂点を移動した+他の作業履歴もある
前回のコラムでは頂点を移動しただけだったので、tweakノードを追加するのみで対処できました。
スキニングした後に頂点移動をして、更にマルチカットなどメッシュの編集をしているときは、本格的に作業履歴の削除が必要です。
まずは後述の「簡単コース」の手順でデータをきれいにします。
大きく頂点が移動しているなら「しっかりコース」の手順を実行します。
どちらのコースでも、追加・移動した頂点のウェイト値は補間で再作成されますので、最後は手動での調整が必要です。
スキニング後に頂点を追加した
前の項目とも被りますが、下の図では頂点を移動してからマルチカットを実行しています。
skinCluster1のあとに「polyTweak1」として頂点移動が、「polyCut1」としてマルチカットが実行されています。
skinCluster1にはウェイト値が記録されています。
頂点を追加したらその分ウェイト値の総数が増えなければいけません。
が、作業履歴を見るとskinCluster1の後に頂点が追加されていますので、ウェイト値の数を増やせません。
FBXはskinClusterに記録されているウェイト値を書き出します。skinClusterより後の編集は書き出しません。
書き出そうとするとエラーが出ます。次のようなエラーを見た覚えはありませんか?
FBXは用語がMayaと違うので、意訳するとこんな感じです。
「FBXは頂点・フェース数が変化する作業履歴のあるメッシュを書き出しません。pCube1は書き出しません。(FBXを開いてもジョイントだけが出ますよ。)pCube1も書き出したければ、書き出す前にDelete Non-deformer Historyを実行してください。」
書き出したFBXを開くと、確かにメッシュがなくなっています。
というわけで作業履歴があるときは、履歴をきれいにする必要があります。
後述の「簡単コース」の手順でデータをきれいにすればOKです。
それで上手くいかなければ「しっかりコース」の手順を実行します。
スキニング後に頂点を削除した
スキニング後に頂点を削除しただけなら簡単です。
次の図のように、エッジを削除したような作業履歴のみある時です。
ポリゴンリダクションのためとか、位置を変えずに頂点数を減らすだけであれば、ウェイト値の数が減るだけです。
FBXに書き出したり、履歴をきれいにするなら後述の「簡単コース」で十分です。
次の図のように頂点を減らして、さらに頂点の位置が変わっているときは注意が必要です。
ウェイト値の数は減っていますが、頂点の位置が変わっています。
ということは、新しい位置に合うスキンウェイトの値が必要です。
「簡単コース」で作業履歴を削除すると、新しいスキンウェイトが適用されますのでとりあえずは行けるはずです。
気にしないといけないところとしては、作業履歴を削除する前と後で変形結果が変わる、ということです。
次のように、作業履歴を削除すると変形の具合が変わることがあります。
下図の例では、スキニング後にエッジの折りたたみ(polyCollapseEdge1)を実行しています。
スキニングで変形するたびにコラプスを実行するので、コラプスされたエッジの位置は、変形後の頂点位置から導き出されます。
作業履歴を削除すると pCylinderShape1 がなくなります。コラプスしたエッジもスキニングで動かすので、位置が微妙に変わってきます。
後でまた説明がありますが「デフォーマ以外のヒストリ(Non-Deformer History)」を実行するとスキンウェイトのコピーが走ります。
コピー方法は決め打ちになっており、ユーザが選べません。もし他の方法でよりウェイト値がいい感じになりそうなら、「しっかりコース」を試してみてください。
変形後の形状でモデリングしている
スキニング後にモデリングすると、ついついジョイントを動かしたあと戻さないまま作業してしまうことがあります。
「ジョイントを動かして変形」→「マルチカットで切れ目をいれる」というようなパターンです。
ジョイントで曲げた時の形に合わせて、マルチカットで切れ目を入れています。(中図)
マルチカットするとき、エッジや頂点は選択せずに、空間に切れ目をいれるようにしてカットしています。
ということは、変形する前の形(左図)の位置ではマルチカットの切れ目が入りません。
「デフォーマ以外のヒストリ」で削除すると、実はバインドした時の形に戻してから処理されています。
左図の状態で処理されるため、エッジが消えます。(右図)
こんなときは「しっかりコース」で対応します。
(しっかりコースはバインドポーズに戻さないで、この形のままバインドします。しっかりコースでも対応出来ない場合があります。)
頂点の位置が大きく異なっている
「デフォーマ以外のヒストリ」は内部的にスキンウェイトのコピーを行うため、頂点の位置が大きく異なると、スキンウェイトが以前と変わります。
理論的にはまあまあいい変形になるはずですが、元のウェイト値は保たれません。
大きく位置が変わっている頂点は、あとでウェイト値を編集します。
もしスキンウェイトのコピー方法を変えることで改善する見込みがあるなら「しっかりコース」で対応します。
スキニング後にいっぱいメッシュ編集をして、もうワケがわからない…
ああ、こちらに長蛇の列が出来ているのが見えています。
頂点を追加したし削除もした。なんならブーリアンも実行したし、ベベルも使ったぜ!もうワケがわからないぜ!!
実際のところ、作業現場では大抵の場合こちらにハマリ込んでいるのではないでしょうか?
上手くいかない可能性が高いですが、とりあえずは「簡単コース」を実行します。
ダメなら「しっかりコース」を実行します。
対処方法 簡単コース:「デフォーマ以外のヒストリ(Non-Deformer History)」を使う
メッシュを選択して次を実行します。
「編集 > 種類ごとに削除 > デフォーマ以外のヒストリ(Edit > Delete by Type > Non-Deformer History)」
これだけでOKです。はい、いつもの手順です。
バインドポーズに戻す必要はないです。バインドポーズがなくても大丈夫です。
せっかくなので内部的に何を行っているか説明しますと、大まかに次の手順で処理をしています。
① デフォーマのノード状態を変更して、デフォーマが適用されないようにします。
→ バインドした時の形で、③の作業履歴が適用された形状になります。(変形した形でモデリングを進めていた場合は要注意!)
② 編集されたメッシュを、中間オブジェクト(変形前のメッシュ)と置き換えます。
→ スキンウェイトを転送し直します。中間オブジェクトと新しいメッシュ間で、コピースキンウェイトと同じように転送します。
頂点数が変わらなければ「レイキャスト(+対象となるジオメトリが見つからなかった頂点ではClosest point on surfaceを適用)」、
頂点数が違えば「サーフェス上の最近接ポイント(Closest point on surface)」で実行。
(頂点の位置が大きく異なる場合は上手くウェイトが転送されません!)
③ 不要な作業履歴を削除します。
「簡単コース」で対応できなければ、次の「しっかりコース」でデータをきれいにします。
対処方法 しっかりコース
しっかりコースは自前でスキンバインドをやり直して、スキンウェイトをコピーする方法です。
① バインドポーズに戻します。バインドポーズがなければ、今の形のままか、バインドポーズにしたいポーズにしておきます。
② メッシュを複製します。(これが、今後新しく使うメッシュとなるように作業を進めます。)
TRS値をフリーズしたいときは、このタイミングでフリーズしておきます。
重要:複製したメッシュを選択すると、アトリビュートエディタに「メッシュ名+Orig」といった、不要なメッシュの履歴がありますので、削除しておきます。(これをしないと、メッシュデータがバイバインです)
削除の仕方ですが、「Orig」という名前のメッシュをアトリビュートエディタで表示して、下にある「選択 (Select)」ボタンを押します。続けて「Delete」キーで削除します。
③ ②で複製したメッシュを、元々のスキニングしていたジョイントにバインドします。
④ 複製元のメッシュ、複製したメッシュの順で選択して、「スキン > スキン ウェイトのコピー(Skin > Copy Skin Weights)」を行います。
オプションは「サーフェス上の最近接ポイント(Closest point on surface)」、「1対1(One to one)」にします。
同じジョイントで、最も近いメッシュ同士でコピーされます。これで上手くいかない場合は、好みでオプションを変更してみてください。
頂点の位置がかなり変わっていても、UV座標が変わっていなければ「UV空間(UV space)」にすると、割と上手くコピーできます。
(ここでは複製元のメッシュからスキンウェイトをコピーしていますが、Mayaの内部処理ではメッシュの編集が反映されていない、skinClusterの履歴の時点でのメッシュ形状からコピーされている点にご注意ください。)
⑤ 複製元のメッシュを削除します。
④では、複製元のメッシュのスキンウェイトをコピーしています。
この手順を「ウェイト値の書き出し・読み込み」に置き換える事もできます。④を下記の手順に置き換えてみてください。
④-① スキニングされたメッシュを選択して「デフォーム > ウェイトを書き出し...(Deform > Export Weights...)」を選びます。
④-② 書き出したいスキンウェイトのノードを指定し、ファイル名を指定します。最後に「書き出し(Export)」または「適用(Apply)」を押してウェイトをファイルに書き出します。
注意:2019以降で「JSON」の結果がおかしいため、XMLの使用をおすすめします。
④-③ 新しいメッシュを選択して「デフォーム > ウェイトを読み込み...(Deform > Import Weights...)」を選びます。
④-④ 先ほど書き出したファイルを指定して「読み込み(Import)」または「適用(Apply)」を実行して、スキンウェイトを読み込みます。
ウェイトの読み込みオプションの、マッピング方法の違いは以下のとおりです。
「インデックス(Index)」にすると、もともとあった頂点にのみウェイトを設定します。(頂点番号が同じところにだけウェイトをインポートします。)
増えた頂点にはウェイトが適用されません。(0.0になります。これは要注意です)
「オーバー(Over)」にすると、インデックスと同じように頂点番号が同じところにだけウェイトをインポートします。
増えた頂点の部分は、既存のスキンウェイトを残します。(こちらのほうがインデックスより安全。でもなんかきちんと置き換わらないときがある?)
「ニアレスト(Nearest)」では近接した頂点のウェイトを適用します。頂点番号は見ないので、位置が大体一致しているときなどに使います。(なんかクオリティが微妙ですけど?)
スクリプト版
「簡単コース」や「しっかりコース」を毎回思い出して、手動で行うには手順が長いのでMELスクリプトにしました。
すごくややこしくなっているデータでは動作しないかもしれませんので、そのときは手動でどうにかしてください…。
複数バインドポーズがあるときとか、同じジョイントに複数のメッシュがスキニングされているとか、あまりテストしていません…。
MELスクリプトの中身を全てスクリプトエディタにコピペして実行すればUIが出ます。あとはなんとなくわかると思います。
細かい使い方はスクリプト内の説明を見てください。
まとめ
ずーーーーーとこのあたりの作業手順はモヤモヤしていて、ユーザの方々からも頻繁に聞かれるところでしたので、今回手順をまとめてみました。
どういったモデリングをすると、何が起きるのか、どう対処すればよいのか、説明する良い機会ですので、あえて各状況でご紹介しました。
実は結局のところ、とりあえず「簡単コース」でやってみて、上手くいかなければ「しっかりコース」で一つずつ手順を確認しながら進めればいい、というだけです。(洗濯機?)
逆に、遠回りでも確実に作業をしたいなら「しっかりコース」だけ行えば大体大丈夫です。
メッシュの編集はこれで概ねOKです。
メッシュのTRS値だけをフリーズしたいときや、ジョイントを移動、追加などするとまた手順が変わってきますので、そのあたりは次回以降でご紹介します。