<< TOP



は・じ・め・て・の  ICE Kinematics その3
ICE IK (逆運動学)
 (My First ICE Kinematics ; ICE Inverse Kinematics)
                

 プロローグ
      今回は、Softimage 2011 から正式サポートしました ICEの Kinematics 機能 について その3 です。

     ここからは、更に発展して、ICEで動く インバース・キネマティクス (IK) の設定をしてみたいと思います。
    だんだん複雑なものになって行きますが、すでに 多くのサンプルや情報があるので、それらを参考にしつつご紹介します。
    Rigを組むような人であれば関心は非常に高いのではないでしょうか。
    リガーが アニメーターやモーキャプスタッフと相談して、従来よりも優れたRigを作成できる可能性を・・・秘めていますよ。
     ここでは、その基礎になるようなことが伝えられたら・・・と思っております、ハイ。

    ではでは、ICE で作る IK をつくりはじめしょう ♪♪

    1 )  ボーンの用意
     > 事前情報と便利ツール
    2 )  2ボーンIK
     > 2ボーンIKの設定方法
     > 2ボーンIKの高速化
     > オフセットの考察
     > UpVectorの考察
    3 )  ICE の エンベロープ
     > Dual Quaternion Deformation の設定方法
     > Nullボーン時の対応方法
      パソコンのスペック WindowsXP SP3、 Intel Core2Duo 3G、 RAM; 3G、NVIDIA Quadro FX1700




ボーンの用意
 事前情報と便利ツール
     まずは、少し前TIPS
    キャラクター・セットアップ、つまりボーンの設定ですが、Softimageで便利な機能の1つに、エンベロープ > リファレンスポーズの設定 があります。
    骨構造体(Rig)に対してエンベロープを設定した後に骨構造位置を変更させたり、エンベロープを骨に付け直したりする時に重宝する便利な機能です。
      >> ヘルプで [リファレンスポーズの変更] を参照

    !! 作成>スケルトン から作った、ボーンを選択した状態で
    プロパティー>静止キネマティクス状態 を実行すると Static_KineState というノードが出来、
    ダブルクリックしてPPGを表示すると 値がまだ  の状態です。
    この状態で、エンベロープ>リファレンスポーズの設定 を実行すると、このPPGに グローバルの値 が代入されることが解ります。
    つまり、ボーンにその ”デフォルトの位置” としてグローパル値が設定されたことを意味しています。
    ICEのIK設定時に この Static_KineState をボーン位置 として利用しています。 !!





      既存の骨を ICE用に使うインプリシットのボーンに置き換えてくれる便利ツールを用意することが出来ました。

          スクリプトの提供です。(VBS) ありがたや!!  >> Chain2Bones.vbs 

        スケルトン構造の骨を選択して を実行します。
        自己インストール型になっていますので、自分のWorkgroupとして設定しているディレクトリーなどの Plugins ディレクトリー以下に保存して利用します。
        実行すると、元のボーンの位置で インプリシットの単独ボーンに置き換えてくれます。(名前も継承して欲しかった・・・)
         <注意> 本当に置き換えちゃうので、元の骨が無くなってしまいます。
             必ずコピーを作って、それにこのツールを使ってください。

    少しでも本番っぽさを考え、既存キャラの足ボーンをから インプリシットのボーン を用意してみます。



     ボーン部分だけを選択した状態にして、Chain2Bones を実行すると
    その位置と角度を保ったインプリシットのボーン が抽出できます。
     

      
     各ボーンに名前を付け、エフェクターの位置にNullを作成しておきます。 
    これらすべて並列で置いてあり、階層構造的に親子ではありません。





2ボーンIK
  2ボーンIKの設定方法
      2つのボーンを選択し、プロパティー>静止キネマティクスの状態 で Static_KineState というノードを付けて
    エンベロープ>リファレンスポーズの設定 をしておきます。

     ワールドのセンターの 尖ったボックス 形状の NULL ICETree を設定します。
    ここでは そのICEの設定されているNullを ICERig と命名しています。

    名前とかはサンプルなどと同じにしておくと、そこで使われているツールとかがそのまま利用出来るケースが多いので、真似ッコがいいです ^_^;;

     前頁にて記述した ICEKinematicsをWorkgroup設定していれば、
    タスクを ICEKimematics にすると IK Solvers > 2 BoneIK ノードがあるので それを取り出します。
    上記で用意した、2つのボーン(LThigh , Shin ) と エフェクターの位置にしたNull (LlegEff ) を Exporer から D&D してICEノードを作成します。
     


     IK Solvers > 2 BoneIK ノードを良く見ると、Target Position とは Eff  の位置情報、Bone1と2 は移動値と長さと解ります。

    1) GetDataノードを取り出して、エフェクターからつないで、[Explorer]ボタンから、GlobalTransform の Pos をクリックして グローバルの位置データを設定します。
     そしたらそれを 2BoneIK の TargetPosition に接続します。



    2) GetDataノードを取り出して、LThigh からつないで、[Explorer]ボタンから、
     Static_KineState というノードをクリックして グローバルの位置データを設定します。
     そしたらそれを 2BoneIK の Bone1Transform に接続します。



    3) GetDataノードを取り出して、LThigh からつないで、[Explorer]ボタンから、Length というノードをクリックして 長さのデータを設定します。
     そしたらそれを 2BoneIK の Bone1Length に接続します。



    4)5) 2)3)と同じ事を 2個目の骨(Shin ) にも設定して、Bone2TransformBone2Length に接続します。
    そしたら、2つの骨位置が動き毎に計算された結果を グローバルの位置として設定するので SetDataノードを取り出し、Kine.global が設定している状態で
    各骨からの入力 と 2BoneIKからの計算結果をつなぎ合わせます。



     後は、出力側に Execute が2つあるので、1つにまとめることができる Executeノードを利用して、1つの出力を ICETreeのPort1に接続して完成です。



    ちゃんと動作するか エフェクターを動かして 遊んでみてください。





2ボーンIK
 2ボーンIKの高速化
     さて、上記で動いているので完成・・・・とも思えるのですが・・・・、
    実はキャラクター一体分、それぞれの全部の骨に SetDataでGlobal値を設定すると・・・ 良いパフォーマンスが得られません。
    ICEで期待される高速化を目指すのであれば、ちょっとした工夫を施します。
      それは、一旦バッファーのように 位置データ (例は良く self.BoneTransforms という値名) を格納しておいて、
    そのデータを元にArrayノードを使って配置する方法が取られます。
     この方法を設定するには、またかなりの改造が必要です。  それではいきますよ・・・・。

    まずは、データ格納の箱を作成します。
     Math>Matrix>4x4Matrix と Array>BuildArrayfromConstant を用意してつなぎ、
    それを SetDataで self.BoneTransforms と新しいパラメータを作成してICETreeの最初のPort1に接続します。
    BuildArrayfromConstant のSizeには、確保する配列のサイズを指定しますが、ここでは最低でも骨の数(つまり、2)を設定しておく必要があります。
    実際には、今後の拡張に備え、人体全体に使われているであろう骨の数、例えば150とか設定しておくと良いでしょう。




    ここで最初に宣言していますので、後はこのパラメータにそれ以下で計算される結果がどんどん代入されていきます。

      <追加情報>
        どんどんと複雑になっていってしまう場合、
        ・見た目の簡素化、修正のし易さ、
        ・計算部分とシミュレーション部分との分離
        ・計算/処理の順番を決めておく、
        などの為、別々の ICETree ノードに分けて設定していくようになります。
         例のとしては、こんな具合になります。

               

        当然ですが、Softimageの処理順番に従い、コンストラクションモードの下から順番に処理されます。↑


     さて、お次、Arrayで位置を特定させるには ID値が必要です。
    この部分の説明は は・じ・め・て・の  ICE Kinematics その2 の 位置情報の選択  で既に紹介しています。
    そこでは、Index値(ID値)を変えると、コーンが置かれるArray上の位置が変化した あれです。
     なので、ここでは各ボーンにユニークなID番号を設定する為に、カスタムのプロパティーセットを利用します。

    第1ボーン LThigh を選択して 作成>パラメーター>新規カスタムパラメーターセット を実行します。
    その名前を ICEBoneParams とし、BoneID と ParentID は整数として -1~999 範囲にし
    Length は 浮動小数値 として 0~999 とします。
     


     一度作成してしまえば、コピぺが出来るので、各骨に 異なる BoneID値 を入れておきます。
    今はあとの2つの値はここでの説明に使用していません。

        <追加情報> これは、何かグループ単位で 一括で カスタムのプロパティーを設定したい場合 の参考になります。

      で、 スクリプトの提供です。(VBS) ありがたや!!  >> ConfigureICEBoneParamsProperty.vbs  

        グループを作成して選択状態にしてから このスクリプトを実行してください。
        ICEBoneParams というカスタムプロパティーが自動的に作成されます!!! 
        個々に異なるBoneID値にはしてくれるようですが、他の部分と合わせて自分で再度数値を記入していってください。



     次は、一括でデータを取得しやすいように グループを作成します。
    足2つ (LThigh, LShin) を LegBone1 というグループ を作成して入れ、それを Array に渡すようにします。
       
      <追加情報>
        キャラ全体のグループ、例えば ENV_MainBody というグループがあるのであれば、
        初期設定用の別 ICETree ノード ( Init_ICE_Rig と命名) にて、ENV_MainBodyグループからID値を取得して、
        全体のID(BonesIDs) を最初に設定しておくと良いでしょう。 下図; 一括初期設定例



     さて、最大の山場です。
    このようにノードを組み上げて行きます。(ただし、これだけでは動きまんよ。)



      では始めます。(この作業中、Boneは下図のようにきちんとした位置に表示されません)
    LegBone1 GroupノードをD&Dし、新しいGetDataノードつないで、ICEBoneParams 内の BoneID を取得します。
    その値(Value)をArray > Set in Array の Indexにつなぎ、結果(Result) を SetDataの self.BoneTransforms に接続します。
    それをIceTree の Port2 に接続します。この時点で、 Set in Array  の前の部分を 「値の表示」 にて 数値にすると、
    BoneIDの値がちゃんと取れてることを表示してくれます。



    Array > Build Array を Set in Array  の前に配置し、そのValueに接続します。
    前述の試し動きの時にあったSetDataを削除して
     Bone1の結果を Value1に、
     Bone2 の結果を Value2 に 接続し、
    3個目の Value3 には エフェクトの位置情報を 2BoneIK を挟んで Matrix to SRT → SRT to Matrix から得た Matrix の結果を接続します。
    そして、GetDataで self.BoneTransforms を Set in Array の Array に接続します。



    Build Array からArray出力を 「値の表示」にて Axes にすると その位置と方向が見れます。



     そして最後の仕上げです。
    実は最後に各ボーン毎にもICEを設定が存在します。どのボーンにもICETreeの内容は同じです。
     己にカスタムパラメータで設定していた ID値 と 格納した BoneTransforms から自分の位置を SelectArrayで導き出し、
    それを自分のグローバルの位置として SetData で設定しています。



     全部のボーンに付けるものなので、簡単なコンパウンド化しておきます。(名前を統一しておきます。)
    Bind Deformer to ICE Rig と名前を付け、 タスク を ICE Kinematics/Rig Binding にします。バージョンは 1.3 にしておいてください。
    出来たら、コンパウンドの書き出し で保存しておきます。



        <追加情報> これは、一括で コンパウンドなど ICEノードをICETree作成含めて接続したい場合 の参考になります。

      で、 スクリプトの提供です。(VBS) ありがたや!!  >> BindRigToICEData.vbs  

        グループを作成して選択状態にしてから > メンバの選択 にしておきます。(全部が白色選択状態)
        そして、このスクリプトを実行します。
        全部の選択ボーンに自動的に Bind Deformer to ICE Rig  が ICETreeに接続されています。

         良く使うスクリプトは ツールバー にまとめて、ワークグループに保存すれば直ぐにみんなの共有ツールに出来ますね。



    はい、全ての設定が終了しました。 きちんと動くか遊んでみてください。



     うまく動作しましたら、お疲れ様でした!! OKです。

    最初はなんでこんなに・・、と思うところなんですが、
    一回動いてしまい、事情が解ってしまうと、おお♪、となるといいな・・と言ったところでしょうか・・・。



2ボーンIK
  オフセットの考察
     どこかの付属物としての骨構造体をくっつける場合の考察です。

    は・じ・め・て・の  ICE Kinematics その1 の オフセットを付ける Matrix Offset use を利用すると簡単です。
    オフセットの値を知る為に仮に作成したNullを HipPlate1の子供にして値を知ります。
    ICETree上に HipPlate のグローバルトランスレーション を持って来て、Matrix Offset use の InputMatrix につなぎます。
    オフセットを付ける第1ボーンの LThigh のStaric_KineStateからのMatrixを MatrixtSRTで回転とスケール値 を Matrix Offset use にそれぞれつなぎます。 
    オフセット値 仮Nullから得た値を記入します。 
    最後に、出た結果の Matrix を 2BoneIKの Bone1Trasform に接続します。



     これで腰骨を動かすと 第1ボーンの LThigh が動くのを 試してみてください。




2ボーンIK
 UpVectorの考察
     これも骨の方向を制御するもの、としての考察です。 (中級レベルに”もってこい”のサンプルです。)

     第1ボーンのオフセット値の後に差し込む形でボーンの方向を変えてみました。
    UpVector用のピラミッド表示のNullはやはり並列に置いてあります。



     サンプルとしているのは Kinematics>LookAt というコンパウンドを展開して中にある Point Pose at Position を編集したものです。



     更に Point Pose at Position を展開すると、下図のようになっています。
    入って来るUpVectorの位置から方向を導き、それを回転値として計算して 第1ボーンのグローバル値にする ということが想定できます。



      ちょっとした改善が使い易すさと、ICEの機能の理解を深めることになります。



     変更点は、入って来るUpVectorの位置が骨の前か後ろかを If でつなぎ、Flipにチェックを入れると後ろになるようにしています。
    これだけなのに、UpVectorのX軸移動方向とは逆方向に骨の向きがちゃんと回転します。前にある場合は位置を追従して回転します。

     その下の BuildArray は、第1ボーン→UpVector→Effector の位置順にオレンジ色の線を描画しているだけのものです。
    If ではなく Andですが、チェックを入れると線が描かれ、外すと消えます。
    こうしたちょっとしたことが アニメーターに使いやすいツールになるでしょう。

     思うような動きになっているかは、試してみてください。
    もし、UpVectorの動きが他のオブジェクトと追従して動いて欲しいなら、HipPlate1 の子供にしてみたはいかがでしょうか。
     


      完成されたものではありませんが、試してもらって良いです。
     少量の変更なので、V1.2としてコンパウンドを書き出しました。 > Point Pose at Position.1.2.xsicompound


ICE の エンベロープ
 Dual Quaternion Deformation の設定方法
     さて、ボーン構造まで出来たとして、パフォーマンスを調べると次に重いのは、エンベロープだったりするのです。
    そこで、エンベロープの計算もICEにしてみる というのは興味ありませんか?
    しかも従来とは違って、色々と工夫の余地があり、どのようにエンベロープの処理するかをも設定できるのです。

     ここでも2個の ICE_Tree を設定します。ウェイト値の処理とエンベロープの処理です。





      脚用のポリゴンを用意し、サブディビジョンサーフェイス (+キーが2回とか) がかかってる場合は 元のポリゴン形状に戻しておきます。
    脚の骨のグループ LegBone1 が用意してあります。これを使って通常のようにエンベロープを 脚ポリゴンに設定します。
    エンベロープ>エンベロープの設定>グループのピック、右マウスボタンで決定。
     
     今回は脚しかないので LegBone1 をボーンのグループとしてD&Dして来て、
    Skinning > CalucateDeformerWeight につないで ICE_Tree に接続します、 
     以上です。 なんて簡単な・・・・


        
      いや、ちゃんと 解説します。
     この処理で、 Self.EnvelopeDeformerIndices と Self.EnvelopeWeights というパラメータを用意しています。
    EnvelopeDeformerIndices は ウェイトの種類を数字化しています。 EnvelopeWeights は文字通りウェイト値ですね。



    CalucateDeformerWeight の中を見てみると、最後に SetDataでそれぞれの値を代入しています。
    「値の表示」 してみると各値がちゃんと取れているのか見ることができます。


     2個目の ICE_Tree を作成して、名前を Envelope_ICETree としてみました。
    今回は脚しかないので LegBone1 をボーンのグループとしてD&Dして来て、
    Skinning > Dual Quaternion Deformation の Deformer Group In Name につないで Envelope_ICETree に接続します。
    通常のEnvelopeOperatorを無効にして、エフェクターを動かしてちゃんと動くか確認します。
     以上です。 なんて簡単な・・・・



     いや、ちゃんと 解説します。
     Dual Quaternion Deformation は他サイトで 現在はV2.0 が公開されていますので取得してください。
    中を見ると結構なノードがありますが、EnvelopeDeformerIndices と EnvelopeWeights を使って、PointPositionのデータを計算しています。
    変形方法が選択になっていて Dual Quaternion Skinning でないと曲がった時の形状が細くなったりしてしまいます。
    もちろん サブディビジョンサーフェイスにも対応していますので、+キーを2回押して滑らかにしてもきちんと変形しています。
     複数のエンベロープ・ウェイトがある場合はどれかを選択できるようになっています。



ICE の エンベロープ
 Nullボーン時の対応方法
     さて、最後に NullをRigに使っていて、ボーン構造となっている場合、
    上記 CalucateDeformerWeight の中では Length の値を取得しているので、Null に無い Length値 が取得出来ず、
    そのままでは動かないことが解ります。
     ならば、このページで紹介しています カスタムパラメーターに Length の値をちゃんと記入してあげて、それを取得すれば良いと気がつきます。
    NullボーンのグループをD&Dし、そこから カスタムパラメーターの LengthをGetDataし、それを Self.Length にSetDataします。
    その間を 「値の表示」 にしていみると、ちゃんと得ていることが確認できます。
    そしたら、その値を CalucateDeformerWeight のLengthの値に代入すれば OK です。
     え?そんな接続部が無い? いやいや・・・作ったまでです。



     中を見ると、内部で Get .Length となっているので、そこだけ外部接続にして その名前を Length  と変えただけです。



     Nullの骨であっても、その表示がボーンらしい みたいな 一工夫として
    X軸方向のNullなら、X軸スケール値 の 半分が X軸のオフセット位置 なんて使われ方もあるようです。





      という訳で、正しく動いた場合のサンプル画像です。





     すでに多くのサンプルやコンパウンド、スクリプトが存在しますので、 
    先人達の知恵 を うまく活用して 自分の目的の動きになるように組み合わせる ・・・ というのが ICEのうまい使い方ではないでしょうか。
    つまり、 ”うまく組み合わせられるように何をしているのかを理解すること” が ICEの使い方の くせ とか こつ になるのかも知れません。




     という訳で、次回は ICEのスプリングとかコリジョンとか 予定してるんですが・・・。

      乞う、ご期待!!