前後左右の動きに分解してスカートのリグを作ってみる

こんにちは、ガレージキット好きの新人、石垣です。

今回は、Autodesk Mayaにおけるスカートなどのめり込み回避用のリギングの際に、私が行った実装方法の例をご紹介いたします。

スカートのめり込み回避のため、足の挙動に合わせてスカートを動かすようなリグを組んだ場合、スカートの骨と足の位置関係によっては、ある程度の角度から動かない様、制限をかけたいことがあると思います。
例えば、前部分のスカートの骨は、足がキャラクター後方に回ったとしても、真下の向きよりも後ろ側に動いてほしくないし、右側のスカートも同様に左側へ挙動してほしくないと思います。

今回の例は、この制御を回転値の制限などではなく、座標値に置き換えた向きとpairBlendノードを利用しためり込み回避用のリグになります。


こちらの記事に関して、@44heee様に検証・ご質問いただき、一部記載内容を修正させていただきました。
検証と質問内容について当ブログで紹介したいとお願いしたところ、内容を以下ブログにまとめていただきました。
https://44hero.github.io/tech_memo/MAYA/utilityNodeを使用した,%20めり込み回避するスカートrig/
@44heee様には、この場を借りてお礼申し上げます!


まずは、実装の結果を

blob

blob

手順としましては…
① 足の回転を別のジョイントにコネクションを行う。
② 回転の向きをロケーターを利用して座標値に変換する。
③ 変換した座標値をpairBlendノードのウェイトに、コネクションしたジョイントの回転値をinRotate2にそれぞれコネクションする。
④ トランスフォームノードを介してコンストレインなどでジョイントに接続する。

というような手順になります。

その他の方法について

何故こういった実装方法を行っているのかという点についてですが、オイラー回転のコネクションを使用した方法等では、多くの問題点が存在するからです。
一例がこちら…
Z軸回転のコネクションのみを行った場合

ある程度回転した所で、スカートの挙動がフリップしたように動いているのがわかります。

上記の例では、ik制御とコンストレインによる角度計算で、角度が180度フリップしていることが原因で、コネクションされた角度が想定外のものになってしまうためです。
このようなオイラー角の接続は「向き」を保証するものではない為、ジンバルロックなどにより正しい角度を表すことができない場合があるわけです。


実装方法

ということで、実装方法の紹介です。

① ジョイントツリーの作成

(今回PrimaryAxisはX軸にしています。)

~~~
<追記:2020/03/24 山本>
足のジョイントについては、子階層方向をX軸+、Z軸方向をメイン回転軸とし、今回の例ではY軸+方向を正面に向けました。

また、スカートの軸方向についても同様に、子階層方向をX軸+方向、z軸方向をメイン回転軸とし、下図のような軸方向で設定しました。

~~~

② 足のジョイントの回転値を受け取るジョイントや必要なロケーターを作成

こちらで作成しているものの階層はこのような形になります。

├─SourceJoint
│  ├─SourceJoint_End
│  └─WeightLoc_Source
└─WeightLoc

SourceJointには足のジョイントの回転をeulerToQuatノードからquatToEulerノードを介してコネクションを行っています。

また、階層内にあるWeightLoc_SourceとWeightLocは下の画像のような接続を行って、向きを座標に変換しています。

~~~
<追記:202/03/24 山本>
SourceJointのジョイントツリーも、子階層方向にX軸+を向ける形で作成します。
ジョイントの長さはここでは特に指定はありません。 後で確認しやすくするために、適度にX軸方向に伸ばしてあげるとよいと思います。

ただ、WeightLoc_SourceとWeightLocについては、
tx,ty,tz = 1.0,0.0,0.0
の位置に設置してあげるとよいです。
WeightLocはWeightLoc_Sourceの位置を取得して、SourceJointの回転をベクトル値で表すためのノードになります。
normalizeされたベクトル値のほうがベクトルの長さの影響を受けないため、この例での位置は上記の位置が望ましいと思います。
~~~

<角度の座標変換について>

「角度」を前後・左右の2要素に分解しようとすると、オイラー回転では回転順序を加味する必要があります。
しかし、「角度の方向」を3軸のベクトル、すなわち「座標 x、y、z」として考えると…

・前後=yz平面では、「座標y、z」
・左右=xy平面では、「座標x、y」

というように、解釈が簡単になります。
こうすることで、
ジョイントが前後左右にどれだけの向いているか
…を、要素分解して表すことが可能になります。

③ 最終的に回転値をジョイントに受け渡すためのトランスフォーム等を作成

腰などに追従するノード
    └─_TransOffset …Offset用ノード
        └─_TransNode …入力用ノード
            └─_Connect …出力用ノード

上記では、対象のスカートジョイントごとに、このような階層構造を構成します。

_TransOffset,_TransNodeは足のジョイントと同じ方向を向かせています。
こちらについてはpairBlendからの接続を行う際に、接続先のアトリビュートの回転値が0の状態になっていないと結果が望ましくないものなる為、_TransOffsetと_TransNodeを同じ位置と向きに配置してアトリビュートが0の状態を作っています。

一方で、_Connectは受け渡すスカートのジョイントと同じ方向にします。
これは、_ConnectとスカートのジョイントをorientConstraintで接続した際、offsetの値が入らないようにするためです。
それは、offsetに不用意な値が入っていると、挙動の結果が望ましいものにならない事がある為、このような措置が施してあります。

④ ロケーターの移動値をpairBlendノードのウェイトに使用するために、ノードを構築

値の設定ですが、clampノードはRが-1~0,Gが0~1,Bが0~1を出力するように値を設定、multiplyDivideノードはinput2Xのみ-1<訂正 2020/03/24 山本>clampノードはRが0.0~1.0,Gが-1.0~0.0,Bが-1.0~0.0を出力するように値を設定、multiplyDivideノードはinput2Y,input2Zに-1をそれぞれ設定してください。
こちらのような接続や値の設定を行う理由ですが、回転の向きを座標変換した値を前述の通りx,yそれぞれの座標値を0~1,-1~0の4つに分ける為にclampノードを使用しています。
また、その後にmultiplyDivideノードを使用しているのは4つになった値をpairBlendのweightに使用する関係上、出力結果を0~1のみにする必要がある為です。

⑤ 前後と横用のpairBlendノードを作成

前後用・左右用のpairBlendノードを作成し、画像のように必要な接続を今まで作成したノードから接続を行います。
また、横に関しては横のみではなく前後を多少ブレンドした方が良いので、それ用のpairBlendノードも作成、接続も行います。

最後にpairBlendノードのoutRotateから接続用のノードである_TransNodeのrotateへそれぞれ接続を行い、
その子階層にある_Connectと名前の付いたトランスフォームノードからジョイントにオリエントコンストレイン等で接続を行えば完成です。

これで足の挙動に応じてめり込み回避が可能なスカートのリグが完成しました。


まとめ

今回はスカートなどに使えるめり込み回避用のリギング方法の一例を紹介しました。紹介したものからさらにソースとなる回転(今回なら足の回転)のBendの抽出を行い、足の捩れがスカートに入らないようにしたり、左右のジョイントが近いところはそれぞれpairBlendでブレンドを行い、一方の動きに合わせてもう一方が少し引っ張られる。そんなリグに仕上げるのもいいかもですね。

Author: kota.ishigaki