執筆者:広森
映像業界を経てモノリスソフトへ入社。 以来、テクニカルアーティストとして主にリギング・セットアップ関連の業務を担当。 好きな飲み物は赤ワイン。
TECH BLOG
こんにちは。モノリスソフト テクニカルアーティストの広森です。
今回はMayaで「リグ初心者」の方に向けたツイストジョイントを作成する手順を書いてみようと思います。
ツイストジョイントを例に記載していますが、考え方は色々な場所で使用できる方法です。応用ができるので無駄にはさせません。
"quaternion" "三角関数" "Matrix"など頭を痛くさせてしまう用語は本文では出てきませんので安心してお読みください。
この部分ではこの記事で出てくる以下のワードについて説明します。既にご存知の方は読み飛ばして頂ければと思います。
ツイストジョイントとは以下の画像をご覧ください。
少ないジョイントのみでスキニングをしてしまうとポリゴンが極端に細くなってしまいます。この細くなる状態を緩和するためにジョイントを追加します。
また、特定の回転だけの影響を受けたい場合にも設定をします。
multiplyDivideとはこの記事で使われる計算ノードの一種です。Mayaでリギングを行う際に使用したり、マテリアルで色を加工したい場合に使用することが出来ます。
Mayaの基本理念としてメッシュやジョイント、カメラやマテリアルなど全てノードで構成されています。その為、私達デザイナーでもプログラムを書く必要なく、直感的に扱えるようになっています。
対応するノードにはこのmultiplyDivideを使って値を加工することが出来ます。
このノードを紐づける事が出来る機能がNode Editorになります。
メニューバーのWindows > Node Editorから開くことが出来ます。
開いたNode Editorでtabキーを押してmultと打ち込むと候補に"multiplyDivide"と表示されるので、クリックするとmultiplyDivideノードが作られます。
簡単にボタンの説明を行います。
画像の① : ノードエディター内のノードをノードエディター上から非表示にします。ノードの削除は行いません。
画像の② : ノードエディター内に選択しているオブジェクトのノードを追加します。関連するノードも追加される場合もあります。ノードが新たに作成されるわけではありません。
画像の③ : 選択しているノードをノードエディター上から非表示にします。こちらもノードの削除は行いません。
ノードを紐づけるには、以下の画像の赤い丸で囲まれた箇所から、もう一つの赤い丸に向かってドラッグするだけで接続できます。
もっと詳細が知りたい方は、公式のドキュメントをご確認ください。
Autodesk、ノードエディタ(Node Editor)の基本
今回の記事で作成する箇所は、肘から手首にかけてのジョイントを想定しています。以下の画像のような階層構造で作成しておきましょう。
配置している全てのジョイントは扱いやすいように"Rotate"と"JointOrient"アトリビュートには0を設定してあります。
ジョイントの名前と配置は以下の画像の状態です。ネーミングルールは分かりやすいものをつけてください。
手首のジョイントである"wrist_L_JNT_00"が動いた際に"elbowTwist_L_JNT_00"が半分動いてほしいので、画像の赤線である"wrist_L_JNT_00"の"RotateX"を同じ軸方向な"elbowTwist_L_JNT_00"の"RotateX"に"multiplyDivide"で半分にした計算。つまり0.5をかけた状態で接続してみましょう。
ノードエディタで接続して回した状態が以下の状態です。うまくねじれていそうですね。
ただ、特定の方向では捻じれてほしい箇所が捻じれていません。
なぜこのような現象が起こるのでしょうか。
3Dソフトでは2種類の回転方法があります。その片方の回転方法がオイラー回転と呼ばれる手法です。
X,Y,Zの3つの値を扱って回転表現をします。人間が扱うには直感的で分かりやすい手法ですね。ただこの回転の手法には問題があります。
以下の画像内の箱は同じ方向を向いてますので、当然回転値も同じはずです。確認してみましょう。
実際に確認した画像がこちらです。
中の回転値がおかしい・・・・・見た目は一致しているのに・・・・
誤差とは言えないような膨大な数値が入っています。
今回たまたまこうなってしまっただけで、2通りだけであれば法則が見つけることが出来るかもしれません。
またしても違う数字が入ってしまいましたね・・・・
このように、この回転方法では最終的に軸方向が同じ向きでも違う値が含まれてしまいます。鋭い方は気が付いたかもしれませんが、360度ずつ回転しているので回りきってしまい1周してしまっているのです。
今回は画像を作りやすいように360度で作成したためこのような形になりましたが、全ての回転軸でこのような現象は起こりえます。
ここに回転順序などを加えてしまうと頭が痛くなってしまいますね。
オイラー回転の値では欲しい情報を取得することが出来ませんでした。ここで改めて達成したい内容を考えてみましょう。
ざっくりまとめるとこうなりますが、これだけでは解決の糸口が掴めないのでもう少し深く掘り下げてみましょう。
先ほど考えた達成したい内容では適切にねじられてほしい定義が曖昧なので、実際の手の状態を観察し当てはめて要素を決めてみます。
以下の画像は全て一定の方向から撮影しています。実際に自分の手の平を返しながら見てみてください。指の向きは変えないものとします。
手首のねじれる条件を明確化します。
掘り下げてみた内容をまとめると以下の内容になりました。
この2つの要素から以下の仮説が立てられそうです。
今後の説明をスムーズにするためにこの現象に名前を付けてあげます。
手首の回転に影響を与える回転 = 捻り量
手のひらの方向を決める回転 = 方向
この2つの要素を実際のジョイントに当てはめることが出来れば、問題に対処できそうですね。
先ほど3つの箱を用いて説明した、「軸方向が同じ向きでも、違う値が含まれてしまう問題」について、ここで改めて確認してみましょう。
現状の回転方法では、手の甲の向きと手のひらのねじれである2つの要素を、3つの数字の組み合わせの回転で表現してしまっているため抽出することが出来ません。
かと言って直感的であるオイラー回転の手法は変えたくありませんし、変更するにはMayaに独自のシステムを作らなければなりません。現実的ではありませんね。
なのでオイラー回転から2つの要素に切り分けてあげましょう。
方向を指し示す要素と捻りを指し示す要素ですね。特定の軸方向にそった捻り量を抽出出来れば適切な情報を取得できそうです。
今回以下の画像でX軸の方向である赤の矢印を方向、青い矢印を捻り量としました。
▼ジョイントの方向と捻りの例
まずは方向だけの回転を抽出してみましょう。Mayaにはデフォルトの機能で特定の位置に向かって回転させる機能がありましたね?
そうです、AimConstraint(エイムコンストレイント)ですね。
▼AimConstraintの例
このコンストレイントを使えば、ターゲットのオブジェクトの方向に指定した軸を向け続けることが出来ます。ターゲットが動けば自動で追従もしてくれます。
方向だけの回転はこれで抽出出来ました。
方向の回転は抽出出来たので残りは捻りですが、以下のように捉えることが出来ます。
オイラー回転は方向の概念と捻りの概念が含まれていると説明しました。数学っぽく言うなら以下の公式です。
方向は決まっており、回転結果であるオイラー回転も制御される骨である"wrist_L_JNT_00"で設定するのでここも決まっています。
後は捻り量が欲しいので式を変形しましょう。以下のような形に変えられます。
これが捻り量になります。1つの回転から2つの要素を出す方法は決められましたね。
回転方法の切り分けの手法は決めることが出来たので、後はジョイントに割り当てる実装作業です。先ほど作成したシーンに以下のジョイントを追加します。
"wristAim_L_JNT_00"ジョイントは方向を決める、"wristRoll_L_JNT_00"ジョイントは捻り量を管理する役割があります。
位置は"wrist_L_JNT_00"と全く同じ場所にそれぞれのジョイントを配置して必ず親子関係を組んでください。
▼ジョイントを追加する位置と名前
設定し終えたらコンストレイントを設定します。
上記の画像であれば"wiristEnd_L_JNT_00"をターゲットにしてAimConstraintを"wiristAim_L_JNT_00"に設定してください。
設定する際のOptionですが必ず"World Up Type"の欄を"None"に設定して下さい。
このWorld Up Typeの欄の内容はAimConstraintの機能で特定の軸方向に向け終えた後に向けた軸をどう補正するのかのオプションになります。
シーンの向きやオブジェクトの向きを設定することも出来るのですが、今回はNoneにしておきます。
Noneにしておくことで他の軸が勝手に補正されないので、欲しい方向だけを取得することが出来ます。
"wiristRoll_L_JNT_00"の扱いですが"wirist_L_JNT_00"と全く同じ方向を向いてくれれば、ParentConstraintやOrientConstraintでもAimConstraintでも何でも良いです。
後は親子関係を設定したので勝手に差分の回転値である捻り量がオイラー回転として"wiristRoll_L_JNT_00"に設定されます。
捻り用のジョイントは半分だけ回転させたいので最初に用意していた"multiplyDivide"に"wiristRoll_L_JNT_00"の"RotateX"を接続してみて下さい。
実際に回転させてみましょう。1軸回転では問題なさそうです。
2軸でも適切な挙動になりましたね。
この構造は"quaternion"の挙動をコンストレイントを使って再現しただけなので、初心者の方には扱いやすいとは思います。複雑な計算や設定も無いので欲しい捻り量がすぐに取ってこれますね。
私も検証ならこの構造を使ってリグを作成することがあります。他のソフトでも似たような設定があれば再現出来るので比較的汎用性も高いです。
しかし、この構造実はデメリットがあります。リガーの方ならお分かりかと思うのですが実は最適化された構造ではありません。
以下の要素が不要な要素です。
不要な要素を無くし、もっと最適化してあげたいと思うようになったら是非挑戦してみてください。
quaternionの知識でくじけてしまった人でも扱えるようにコンストレイントのみを使ってツイストジョイントを作成してみました。
そしてツイストジョイントなどで良くある課題を解消するためのアプローチとして要素を分解し、順番に対処する方法を記載してみました。
この考え方はツイストジョイントだけでなく他の物事にも活かせるので、何かに躓いてしまった方は是非活用してみて下さい。
また、リグに対するハードルや苦手意識が少しでも払拭出来ればと思います。
Autodesk、ノードエディタ(Node Editor)の基本
https://knowledge.autodesk.com/ja/support/maya/learn-explore/caas/CloudHelp/cloudhelp/2020/JPN/Maya-Basics/files/GUID-68E825E4-140B-4B4E-97AC-E1C5E0AA84A0-htm.html
執筆者:広森
映像業界を経てモノリスソフトへ入社。 以来、テクニカルアーティストとして主にリギング・セットアップ関連の業務を担当。 好きな飲み物は赤ワイン。