Mecanim/Humanoidに最適なスケルトン構造とは?
はじめに
Mecanim/Humanoidのモーションリターゲット機能は、極めて強力な機能です。モーションリターゲット機能を使うことで、大抵のモーションはプロポーションの異なる様々なモデルに流し込むことができます。つまりMecanim/Humanoidを使うことで、プロポーションの異なる様々なモデルに対して汎用的にモーションを割り当てることが出来るわけです。
このように強力なモーションリターゲット機能をもつMecanim/Humanoidですが、元となるアニメーションが焼き付けてあるスケルトンの構造によっては、ある一部の動きに不具合が生じることがあります。その不具合は主にスケルトンの『腰』の構造に起因するものですので、Mecanim/Humanoid向けにモーションを作る際に、注意しておくとよいでしょう。
ここでは、Mecanim/Humanoidに最適なスケルトン構造について考察すると同時に、不具合の生じるモーションを、MayaやMotionBuilderに付属するHumanIKを使って修正する方法を紹介します。
さらにMecanim/HumanoidおよびMecanim/Genericで使える、メッシュを削除したスケルトンのみの状態でモーションをFBX出力する際のTipsについても触れます。
※本ブログの内容の初出は、2014年12月に発売されました『UNIBOOK2』です。
Mecanim/Humanoidでうまく再生されないモーションとは?
図1.1うまく再生されないモーションの例
図1.1を見てみましょう。緑と赤のそれぞれの枠で囲まれているモーションは、どちらも同じモーションです。上の緑の枠で囲まれているほうは、Mecanim/Genericで設定したもので、下の赤の枠で囲まれているほうは、Mecanim/Humanoidで設定したものです。
このモーションの場合、下の赤枠で囲まれているほうは、見たところどうやら『腰』の辺りに不具合が生じているらしいことがわかります。
このサンプルはSDユニティちゃんのものですが、この「倒れた状態から腰を大きくフリップして立ち上がる」というモーション以外は、Mecanim/Humanoidでも、Mecanim/Genericでもさほど大きな違いはなく同じモデルに適用できました。しかし該当するモーションだけは、Mecanim/Humanoidではうまく再生することはできませんでした。
スケルトンの『腰』の構造に注意しよう
同じスケルトン構造を持っているモデルとモーションをMecanim/Humanoidで使用しているにも関わらず、時々このように大きく再生結果が異なる場合があります。これらの再生の不具合が発生する原因は、モーションがベイクしてあるスケルトンの『腰』の構造にあります。
図1.2: CenterとHipsが別になっているスケルトン
これらの問題が発生するスケルトンの『腰』の構造は、図1.2のようになっています。『腰』に当たる部分のノードは、図では「Center」と「Character1_Hips」(以下、「Character1_」の部分は省略して、単に「Hips」と書くことにします)の2つのノードからなっています。ここで、
● Centerノード:腰の移動情報(Transform)が入っている
● Hips ノード :腰の回転情報(Rotation)が入っている
このような二重の腰構造を持つ利点は、上半身の階層と下半身の階層が別れていることにあります。下半身の影響を上半身が受けにくいので、特にゲーム向けに手付けでモーションを作っている場合、このようなスケルトン構造のほうが大きな動きのあるモーションを付けやすいという利点があります。
一方、Mecanim/Humanoidに最適なスケルトン構造は、図1.3のようなものです。
図1.3: Mecanim/Humanoidに最適なスケルトン
`図1.3では、『腰』に当たるノードは「Hips」しかなく、実際、Hipsノードには、腰の移動情報(Transform)と回転情報(Rotation)の両方が入っています。
仕様上、Mecanim/Humanoidでスケルトンを構成するノードで移動情報が用いられるのは、Hipsノードのみとなっています。詳しくは本noteの『Mecanim Humanoid の基礎的技術解説』を参照してください。
このスケルトン構造は、MayaやMotionBuilderが搭載しているHumanIKが自動で作り出すスケルトン構造と同じで、特にフルボディIKと呼ばれるタイプのリグ(手足等の身体の末端を動かすことで、全身のバランスに影響が与えられるタイプのリグ)は、このようなスケルトン構造に対して適用されることが多いようです。
Mecanim/Humanoidで利用したいアニメーションデータが、図1.2のような構造のスケルトンに焼き付けられている場合、それを正確に再生したいならば、焼き付けられている状態のアニメーションデータを一旦、図1.3の構造に組み直したモデルにリターゲットし、再度FBXで出力してやる必要があります。以下は、その具体的な手順について説明をします。
Mecanim/Genericを使っている場合
もしMecanim/Humanoidを使わずに、Mecanim/Genericを使っている場合には、『腰』を構成するノードの違いは気にする必要はありません。Mecanim/Genericは、専用のスケルトン構造を持つモデルに、それと同じスケルトン構造を持つアニメーションデータを割り当てるためのシステムですので、どんな構造のスケルトンでもモーションを割り当てることができます。
しかしMecanim/Genericの場合、そのアニメーションデータはそのモデルに対して専用になってしまうので、Mecanim/Humanoidが持っているような高い汎用性はありません。
この辺りは、容量を気にしないで専用性を選ぶか、モデルに左右されにくいリターゲットによる汎用性を選ぶかで決めるとよいでしょう。
モデルのスケルトン構造を組み替え、Mecanim/Humanoid用モデルを作る
スケルトンの階層を一旦、解く
まず図1.3の構造に、アニメーションがついていないモデルのスケルトンを組み替えます。以下の作業は主にMayaで行っています。
図1.4: スケルトン階層の組み替え・その1
図1.4のように、Reference以下の親子階層になっているスケルトンを、まず上半身と下半身にざっくりとわけてしまいます。これらの親子階層はペアレントで構成されていますので、各階層ごとにペアレントを解除すれば問題ありません。
図1.5: 3dsMax由来のモデルの場合
3dsMax由来のモデルの場合、ルートノードであるReferenceのX回転に、−90度が入っていることがあります。これは3dsMaxでは「Z軸が上」であり、MayaやUnityでは「Y軸が上」である座標系の違いを吸収するためのものです。
図1.4のように、ルートノードの子であった各ノード(この場合、Center、Spine、Spine1)のペアレントを解除すると、各ノードのX回転に−90度が入ります。このまま気にしなくてもかまいませんが、アニメーション自体はリターゲットしてしまいますので、この時点で「トランスフォームのフリーズ」コマンドを使って、回転をフリーズしてしまってもかまいません。Reference、Center、Spine、Spine1の各ノードの回転をフリーズすると、X回転はすべてゼロになります。
スケルトンを組み替え、Mecanim/Humanoid用モデルを出力する
続いて、図1.6のように、Spine以下の上半身の階層が、Hipsノードの子になるように、階層を組み替えます。
図1.6: スケルトン階層の組み替え・その2
組み替えが終われば、もはやCenterノードは不要ですので削除してしまってかまいません。
なお以上の組み替えは、SDユニティちゃんの場合、組み替えるノードがスキンにバインドされていませんでしたので、そのまま行いましたが、場合によっては一時スキンのバインドを解除した後で組み替える必要があるかもしれません。それらはモデルによって事情が違いますので、きちんと調べてから行いましょう。
ここまで終われば、図1.3と同じ構造になっていると思いますので、この段階で一度「デフォーマ以外の全てのヒストリ」を削除し、新規に保存しておきましょう。こちらのメッシュ付きのモデルは、Mecanim/Humanoid用のモデルとして使用することができます。
このMecanim/Humanoid用のモデルをFBX出力して、Unityにインポートしておきます。
アニメーションデータをMecanim/Humanoid用モデルにリターゲットする
次に、図1.2のスケルトン構造に焼き付けられているアニメーションデータを、図1.3のスケルトン構造を持つMecanim/Humanoid用モデルにリターゲットします。この工程は、MayaのHumanIKかMotionBuilderで行います。
図1.7: モーションのリターゲット/ソース側の設定
図1.2のスケルトン構造に焼き付けられているアニメーションデータを、「ソース」と呼びます。図1.7は、ソース側のコントロールリグ定義の例です。今回の場合、ソースは、3dsMaxからMayaにエクスポートしたアニメーション付きのモデルデータを用います。
ここで重要なのは、キャラクターコントロールウィンドウの定義タブ内の項目で、
● Reference :ソース側の「Reference」を割り当てる
● Hips Translation:ソース側の「Center」を割り当てる
● Hips :ソース側の「Hips」を割り当てる
のように設定します。
続いて、アニメーションデータを流し込むMecanim/Humanoid用モデルを「ターゲット」と呼びます。図1.8は、ターゲット側のコントロールリグ定義の例です。
図1.8: モーションのリターゲット/ターゲット側の設定
ターゲット側では、
● Reference :ターゲット側の「Reference」を割り当てる
● Hips Translation:なにも指定しない
● Hips :ターゲット側の「Hips」を割り当てる
のように設定します。
具体的なリターゲットの手順は、MayaやMotionBuilderの解説になりますのでここでは省略しますが、『Making of ユニティちゃんステージデモ in ComicMarket 86』の8〜28ページの内容と同じです。ただし今回の場合には、基本的なスケルトンの構造や比率はまったく同じですので、アニメーションレイヤー等を使ってモーションを調整する必要はありません。簡単に言えば、モーションキャプチャデータを流し込むのと同様の方法で、スケルトン構造の違いをリターゲットで吸収してしまうということです。
アニメーションデータを流し込んだターゲット側のモデルをセーブし、Mayaで再度開くと、図1.9の「Character1_Spine」や「Character1_Spine1」ように、元々なかったジョイントが増えています。
図1.9: リターゲット後の整理
増えたジョイントを見てみると、特にアニメーションデータが流し込まれている訳でもなく、しかも元々のロケータノードに並立して存在しているだけですので、削除してしまいます。合わせて元々のロケータノードの名前が変わっていますので、元の名前にリネームします。
図1.10: リネーム後の結果
リネームした結果、図1.10のようになれば終了です。必要に応じて、スケルトンにアニメーションデータをシミュレーションベイクしておきましょう。
ここまでで、図1.3のスケルトン構造にアニメーションデータを焼き付けたシーンが出来たことになります。
メッシュを含まないアニメーションデータのみのFBXを出力する
Mecanim/Humanoidに使うにせよ、Mecanim/Genericに使うにせよ、Unity上で使用するモデルデータとは別に、アニメーションデータのみを含んでいるFBXを出力することで、Unity上で使用するリソースを圧縮したいと思うことはよくあります。
メッシュを含まないスケルトンに焼き付けられたアニメーションデータのみのFBXを出力するためには、アニメーションデータを含むFBXデータを出力するためのFBX設定の他に、以下のような作業をFBX出力前に済ませておく必要があります。
● 元のルートノード「Reference」の親として、グループノードを追加する(これを俗に「ゴッドヌル(God null)」といいます。)
● ゴッドヌルを追加した後で、不要なメッシュの含まれる階層を削除する
● もしブレンドシェイプのキーアニメーションを一緒に出力したい場合には、それが載っているメッシュは削除しない
● 特にMecanim/Humanoid向けにスケルトンのみでアニメーションデータを出力する時には、必ず0フレーム目をバインドポーズにしておくこと
図1.11: アニメーションデータのみのFBXデータを出力する
ゴッドヌルを設ける理由は、これがないと特にMecanim/Genericの場合で、しばしばルートノードをUnityが認識できないことがあるからです。他にも、Mecanim/Humanoidでセカンダリアニメーションが載っている揺れものボーンがある場合、揺れものボーンの座標がおかしくなることがあります。この場合にもゴッドヌルがあると解決する場合があります。
また0フレーム目をバインドポーズにしておくノウハウは、非常に重要なものです。これをしておかないと、Mecanim/Humanoidがアニメーションデータをリターゲットする際に、強制割り当てをするTポーズが乱れ、結果モーションのリターゲット精度が著しく下がります。これはMecanim/Genericでは問題になりませんが、将来の運用を考えると、モーションキャプチャデータも含めて、常に0フレーム目はバインドポーズにしておくことは悪い習慣ではないと思われます。
まとめ
今回は、Mecanim/Humanoidに最適なスケルトン構造を考察しつつ、3dsMaxやSoftimageで作成されたアニメーションで使われている例が多い、腰がCenterノードとHipsノードの二重構造になっているアニメーションデータの扱い方について解説をしました。また最後に、メッシュを含まないアニメーションデータのみのFBXを出力する方法についても解説を行いました。
これらの情報は経験的な情報なので、何故こうなっているのか説明するのはとても難しいのですが、他にも何か興味深い情報をお持ちの方がいらっしゃったら、是非、ご連絡いただければと存じます。
この記事が気に入ったらサポートをしてみませんか?