チュートリアル / 読んで触ってよくわかる!Mayaを使いこなす為のAtoZ
第25回:スケルトンとスキニングのおまけ話
- Maya
- キャラクター・リグ
- ゲーム
- コラム
- チュートリアル
- 中級者
- 学生・初心者
- 教育
- 映画・TV
ここまでジョイントとスキニングの基本知識、実際に効率的にスキニングする方法を見てきました。もうゲームのキャラモデルを良い感じにスキニングできそうでしょうか?今回と次回はスケルトンとスキニングにまつわる、ちょっと説明していなかったお残りを紹介してみたいと思います。の前に、ゲームの話を増やそうということで、まずゲーム制作でのジョイントとスキニングにまつわる話をひとつ。
ゲームではデータの使い回しが多いですし、使い回しの多い方が作業自体の効率も、リアルタイム処理での効率も良くなりますのでとにかくそれを考えながらデータの作成を始めます。
一つのスケルトンの名前ルール、ジョイント位置、ジョイント数などの仕様を決めたら、あらゆる所で使いまわします。しかもゲームはバージョンアップしながら何年も続けてリリースすることもあるので、映像以上にデータの再利用率が高く、なかなかデータの構造を変えることができません。うっかり変えてしまうと、バグとして問題を起こすこともあります。
始めに決めたスケルトンの仕様が延々と残り続けて、最後には「負の遺産」と言われる有り様になることもよくあります。その「負」たる理由は様々ですが、やっぱり「謎の構造」があると良くないですね。すべてのジョイントがメッシュを変形するために用意してあれば良いのですが、不要な親子構造、プログラマとのやり取りの中で追加された謎のルール、その時は必要だったけどのちのMayaのバージョンアップや、プログラムの最適化で必要なくなった何か、そういったものが「負」になり得ます。
しかし何年経っても必ず言えるのは「変形に使用するジョイント」は絶対にスケルトンに必要ということです。ですから、これまで見てきた通り、メッシュの変形に最低限必要なジョイントでスケルトンを作ることが大切です。そうすれば処理のスピードだけでなく、将来のメンテナンス性も良くなります。
将来もっと複雑なアニメーションをさせたりするのは「リグ」がやってくれます。スケルトンをシンプルにすることで、リグのバリエーションを増やしやすくなります。この話は結構、いや、かなりややこしいのでまた今度特集したいと思います。さて、では残りの話に行きましょう。
スケルトン、つまりジョイントを作るのには「位置」「方向」「数」「親子構造」を決める作業があります。このうち特に面倒なのが「方向」です。データをきれいにするために行う、ジョイントのRotate値を0にして、Joint Orientで回転させるという手順。そしてジョイントの進行方向が+Xになるようにするという決め事。そういった仕様が作業を難しくします。
まずは「位置」「数」から始めてみましょう。最初に適当でいいので位置だけ決めるためにジョイントを作ります。ジョイントの方向を気にしなくていいのなら、好きにジョイントを足したり捨てたり移動したりできます。コレを自由にできることが品質向上につながります。
このスケルトンは一時的なものとして「捨てる」ことを前提に作ります。ジョイントの名前も気にしなくて大丈夫です。片側のジョイントができたら、適宜ジョイントをペアレントして、AnimationメニューセットのSkeleton > Mirror Jointで左右対称方向に複製します。
適当にバインドして、変形がうまく行きそうか確認します。スキンウェイトは適当で大丈夫です。全体的な変形の傾向だけ見ます。脇のあたりとか、ジョイントがもうちょっとあったほうがいいかなとか思えば追加してみます。頭の中で想像するだけでは難しいですが、こうして変形してみるとどこにジョイントが必要そうかすぐに分かるのでやって見ることが大切です。
最後にスナップの機能を使いながらジョイントをルートから作り直します。Mayaは作成しているジョイントの方向を見て、自動的にジョイントの角度を設定してくれます。下の左図でハイライトされているジョイントは仮ジョイントにスナップして作り直したジョイントです。右図はそのジョイントの位置をずらしてみたものです。
まあ、軸の方向が微妙にひっくり返ったりしてますが…。少なくともTranslateX以外のYZ値、Rotate値は0のままなので、ずいぶんとデータはキレイです。
ひっくり返っている軸は、Joint Orientに180とか値が入っていると思いますので、これを0にします。
今回の場合Joint Orient Xに180が入っています。ただし180を0にすれば当然子供のジョイントも回転してしまって位置が変わってしまいます。
なので、まず子供をUnparentします。
それからJoint Orient Xを0にします。これなら子供に影響を与えず、Joint Orientを変更できます。
再びParentします。これならジョイントの位置を保ったまま軸の値をきれいにできます。ほかも同じ事です。
ジョイントの位置さえ決まっていればその位置情報を利用できるので、例えばAim Constraintを使ってジョイントの方向を設定することもできます。
あとでコンストレインを捨ててFreeze TransformationsをすればRotate値がJoint Orient値にコンバートされるのできれいなデータになります。
そんな感じで微調整していきます。
モデリングやアニメーションと同じで、こうしてラフなデータから整形したデータを作るアプローチを忘れないようにすると、他のことでも効率的に作業出来ると思います。
1)Paint Skin Weights Toolでスーっとスキンウェイトを設定する。
2)ガタッと音がした方にジョイントを動かす。
3)ペイントをもう一度しようとすると…いないんです。さっきまでそこに白いモノがあったのに、黒くなっているんです。おかしいなーと思ってComponent Editorを見ていると、無いんです。値が無いんです!設定したはずのスキンウェイトが無くなっているんです。
という話です。うむ、震え上がりそうな話です。
実は単純にEdit > Delete by Type > Non-Deformer Historyを実行すれば直ります。何が原因かまでしつこく問い詰めるのがこの連載のニクいところなので、しっかり説明いたします。
バインドした後にSplit PolygonやSmoothなど「頂点数が増える」編集をした場合にこの問題が起きます。ヒストリを見てみるとよくわかります。
先ほどのキューブのヒストリはこういう感じになっています。
Skin Clusterノードはバインドするとできるヒストリでスキンウェイトを記録しています。右隣のノードはバインドしたあとに実行したSplit Polygonのヒストリです。(ノードの種類はpolySplit)
そう、このキューブはバインド後にSplit Polygonを実行していたのです。
ヒストリの各ノードでの頂点数を示すと、こうなります。
既に「あぁ…」と気づかれた方もいるかもしれませんね。Skin Clusterは8頂点分のスキンウェイトしか保存していません。なのでSplit Polygonで増えた頂点分のウェイト情報を記録できないのです。
だからComponent Editorでは値がない状態になっていたのです。論理的には正しいですね。では、何故にPaint Skin Weights Toolではペイントできてしまうのか。それは、頑張っているんです。ペイントが頑張っているのです。でもウェイトを記録する場所が無いので、ペイントをやめたら値はどこかへ行ってしまいます。たぶん内部にキャッシュを持っていて、それを表示しているのではないかと想像しますが。
このヒストリの現象がわかりやすい例は、Cut Faceをした時です。バインドした後にCut Faceしてジョイントを動かすと空間に切れ目が残り続けます。つまり、変形したあとに切っているわけです。
これもEdit > Delete by Type > Non-Deformer Historyすれば、Cut Faceで追加した頂点がSkin Clusterに保存されるようになりますので、直ります。
逆に、例えばSmoothの処理なんかはNon-Deformer Historyをしなければ、細分割した分の頂点にスキンウェイトを割り当てなくてすむわけで、編集の手間が省け、データも軽くなるのでそれはそれで利点があります。
問題が起きたらヒストリを見てみて、Mayaが何をしているか論理的に考えることも重要です。バグっているように思えますが、実際にはとても論理的に処理されています。それが論理的すぎてユーザーにとっての思惑と異なりバグに見えるわけですが…。Mayaに歩み寄って、解ってあげる、ことも大切ですね。
逆にテクニカルな側面から見ますと、Mayaはそういう部分まできちんと探れるように、とてもオープンな仕組みで作られているので、どんな問題が起きても追跡可能なわけです。これは大きな組織で作業する場合、確実に問題をつぶしながら安定してプロジェクトを進めるために重要なことです。もちろん小さなプロジェクトであっても、問題究明が迅速に行われることは良いことですから、そういう面でもMayaを見てみると面白いと思います。
次回は、これも悩みどころなスキンウェイトのコピー、保存の方法を見ていきたいと思います。
ゲームではデータの使い回しが多いですし、使い回しの多い方が作業自体の効率も、リアルタイム処理での効率も良くなりますのでとにかくそれを考えながらデータの作成を始めます。
一つのスケルトンの名前ルール、ジョイント位置、ジョイント数などの仕様を決めたら、あらゆる所で使いまわします。しかもゲームはバージョンアップしながら何年も続けてリリースすることもあるので、映像以上にデータの再利用率が高く、なかなかデータの構造を変えることができません。うっかり変えてしまうと、バグとして問題を起こすこともあります。
始めに決めたスケルトンの仕様が延々と残り続けて、最後には「負の遺産」と言われる有り様になることもよくあります。その「負」たる理由は様々ですが、やっぱり「謎の構造」があると良くないですね。すべてのジョイントがメッシュを変形するために用意してあれば良いのですが、不要な親子構造、プログラマとのやり取りの中で追加された謎のルール、その時は必要だったけどのちのMayaのバージョンアップや、プログラムの最適化で必要なくなった何か、そういったものが「負」になり得ます。
しかし何年経っても必ず言えるのは「変形に使用するジョイント」は絶対にスケルトンに必要ということです。ですから、これまで見てきた通り、メッシュの変形に最低限必要なジョイントでスケルトンを作ることが大切です。そうすれば処理のスピードだけでなく、将来のメンテナンス性も良くなります。
将来もっと複雑なアニメーションをさせたりするのは「リグ」がやってくれます。スケルトンをシンプルにすることで、リグのバリエーションを増やしやすくなります。この話は結構、いや、かなりややこしいのでまた今度特集したいと思います。さて、では残りの話に行きましょう。
もっと早くスケルトンを作る方法
以前ポリゴンモデリングの回で話した、効率を上げたり物事を正確に処理するには「手順を分解して似た作業はまとめてやる」というアレ、スケルトンを作る場合にはどのように作業を分解すれば良いと思いますか?スケルトン、つまりジョイントを作るのには「位置」「方向」「数」「親子構造」を決める作業があります。このうち特に面倒なのが「方向」です。データをきれいにするために行う、ジョイントのRotate値を0にして、Joint Orientで回転させるという手順。そしてジョイントの進行方向が+Xになるようにするという決め事。そういった仕様が作業を難しくします。
まずは「位置」「数」から始めてみましょう。最初に適当でいいので位置だけ決めるためにジョイントを作ります。ジョイントの方向を気にしなくていいのなら、好きにジョイントを足したり捨てたり移動したりできます。コレを自由にできることが品質向上につながります。
このスケルトンは一時的なものとして「捨てる」ことを前提に作ります。ジョイントの名前も気にしなくて大丈夫です。片側のジョイントができたら、適宜ジョイントをペアレントして、AnimationメニューセットのSkeleton > Mirror Jointで左右対称方向に複製します。
適当にバインドして、変形がうまく行きそうか確認します。スキンウェイトは適当で大丈夫です。全体的な変形の傾向だけ見ます。脇のあたりとか、ジョイントがもうちょっとあったほうがいいかなとか思えば追加してみます。頭の中で想像するだけでは難しいですが、こうして変形してみるとどこにジョイントが必要そうかすぐに分かるのでやって見ることが大切です。
最後にスナップの機能を使いながらジョイントをルートから作り直します。Mayaは作成しているジョイントの方向を見て、自動的にジョイントの角度を設定してくれます。下の左図でハイライトされているジョイントは仮ジョイントにスナップして作り直したジョイントです。右図はそのジョイントの位置をずらしてみたものです。
まあ、軸の方向が微妙にひっくり返ったりしてますが…。少なくともTranslateX以外のYZ値、Rotate値は0のままなので、ずいぶんとデータはキレイです。
ひっくり返っている軸は、Joint Orientに180とか値が入っていると思いますので、これを0にします。
今回の場合Joint Orient Xに180が入っています。ただし180を0にすれば当然子供のジョイントも回転してしまって位置が変わってしまいます。
なので、まず子供をUnparentします。
それからJoint Orient Xを0にします。これなら子供に影響を与えず、Joint Orientを変更できます。
再びParentします。これならジョイントの位置を保ったまま軸の値をきれいにできます。ほかも同じ事です。
ジョイントの位置さえ決まっていればその位置情報を利用できるので、例えばAim Constraintを使ってジョイントの方向を設定することもできます。
あとでコンストレインを捨ててFreeze TransformationsをすればRotate値がJoint Orient値にコンバートされるのできれいなデータになります。
そんな感じで微調整していきます。
モデリングやアニメーションと同じで、こうしてラフなデータから整形したデータを作るアプローチを忘れないようにすると、他のことでも効率的に作業出来ると思います。
恐怖!スキンウェイトが消える
Mayaの怪談話、時々聞く恐ろしげな話があります。よくあるのがバインドしたメッシュでの話です。例えば、こういった話を聞いたことはありませんか?1)Paint Skin Weights Toolでスーっとスキンウェイトを設定する。
2)ガタッと音がした方にジョイントを動かす。
3)ペイントをもう一度しようとすると…いないんです。さっきまでそこに白いモノがあったのに、黒くなっているんです。おかしいなーと思ってComponent Editorを見ていると、無いんです。値が無いんです!設定したはずのスキンウェイトが無くなっているんです。
という話です。うむ、震え上がりそうな話です。
実は単純にEdit > Delete by Type > Non-Deformer Historyを実行すれば直ります。何が原因かまでしつこく問い詰めるのがこの連載のニクいところなので、しっかり説明いたします。
バインドした後にSplit PolygonやSmoothなど「頂点数が増える」編集をした場合にこの問題が起きます。ヒストリを見てみるとよくわかります。
先ほどのキューブのヒストリはこういう感じになっています。
Skin Clusterノードはバインドするとできるヒストリでスキンウェイトを記録しています。右隣のノードはバインドしたあとに実行したSplit Polygonのヒストリです。(ノードの種類はpolySplit)
そう、このキューブはバインド後にSplit Polygonを実行していたのです。
ヒストリの各ノードでの頂点数を示すと、こうなります。
既に「あぁ…」と気づかれた方もいるかもしれませんね。Skin Clusterは8頂点分のスキンウェイトしか保存していません。なのでSplit Polygonで増えた頂点分のウェイト情報を記録できないのです。
だからComponent Editorでは値がない状態になっていたのです。論理的には正しいですね。では、何故にPaint Skin Weights Toolではペイントできてしまうのか。それは、頑張っているんです。ペイントが頑張っているのです。でもウェイトを記録する場所が無いので、ペイントをやめたら値はどこかへ行ってしまいます。たぶん内部にキャッシュを持っていて、それを表示しているのではないかと想像しますが。
このヒストリの現象がわかりやすい例は、Cut Faceをした時です。バインドした後にCut Faceしてジョイントを動かすと空間に切れ目が残り続けます。つまり、変形したあとに切っているわけです。
これもEdit > Delete by Type > Non-Deformer Historyすれば、Cut Faceで追加した頂点がSkin Clusterに保存されるようになりますので、直ります。
逆に、例えばSmoothの処理なんかはNon-Deformer Historyをしなければ、細分割した分の頂点にスキンウェイトを割り当てなくてすむわけで、編集の手間が省け、データも軽くなるのでそれはそれで利点があります。
まとめ
今回紹介したことは、これまでやってきたことの応用です。効率的に作業をするためには、やることを単純にして段取りを分けるのが大切です。問題が起きたらヒストリを見てみて、Mayaが何をしているか論理的に考えることも重要です。バグっているように思えますが、実際にはとても論理的に処理されています。それが論理的すぎてユーザーにとっての思惑と異なりバグに見えるわけですが…。Mayaに歩み寄って、解ってあげる、ことも大切ですね。
逆にテクニカルな側面から見ますと、Mayaはそういう部分まできちんと探れるように、とてもオープンな仕組みで作られているので、どんな問題が起きても追跡可能なわけです。これは大きな組織で作業する場合、確実に問題をつぶしながら安定してプロジェクトを進めるために重要なことです。もちろん小さなプロジェクトであっても、問題究明が迅速に行われることは良いことですから、そういう面でもMayaを見てみると面白いと思います。
次回は、これも悩みどころなスキンウェイトのコピー、保存の方法を見ていきたいと思います。