<< TOP



Twitter 110 Followers 記念
は・じ・め・て・の  ICE Simulation その2
スプリング/コリジョン編
 (My First ICE Simulation)
                

 プロローグ
      前回の続き、より複雑な処理を実現させる ICEによるシミュレーション機能 についてに記述しようと思います。

     前頁の続きで、パーティクル間の長さが変わるので、
    それに応じて骨の長さも変わる いわゆる ストレッチボーンの解説を追加します。

     それに続いて、Strand を利用したより複雑な コリジョン付きスプリング を紹介します。
    ただし、やはり研究段階のものなので、もっともっと良い設定もあることでしょう。

     ICEのスプリングやコリジョンの制御方法を学び、 位置データ制御をICEで行う際のより深い技術を習得しちゃいましょう!!

    2)  位置データとしてのパーティクル
     > Spring Force の利用6

    3)  位置データとしてのストランド
     > Strand の利用1
    > 髪の毛
      パソコンのスペック WindowsXP SP3、 Intel Core2Duo 3G、 RAM; 3G、NVIDIA Quadro FX1700


位置データとしてのパーティクル

 Spring Force の利用6
      実は、前頁 "SpringForceの利用3" の続きです。
     各パーティクル間の距離は 当然スプリングなので伸縮しますので、ボーンの長さもそれに応じて変化させたいところです。


           追加情報 上図 ID to Location の次の GetPoinPosition のノードですが、
          Deformationタブ > Getters > Get PointPosition という既存ノードでは左側に接続ポイントが無いよ? とのことで・・・、
          NoNo,この GetPointPosition は、 ツール タブ > DataAccess > Get Data にて PointPosition を取得したノードです。(似てるけど間違えないように・・・・)
           追加情報 前頁にて、データ格納用の BuildArrayFromConstant につなぐ 4x4Indentity ってその名前で探すと無くて、
          実は ツールタブ内 > Math > Matix > 4x4Matrix  というノードを取り出すと 4x4Indentity って書いてあります、ややっこしーですね。

     
     下図では [値の表示] をすると、ちゃんと骨の長さが取れているのが 画面に表示されている例です。↓
    変更を加えるのは、Constraint_ICETree と名付けた方です。



     まずは、5個の値が入る箱を作成しておきます。
    Array > Build Linearly Interpolated Array (スカラ配列)  を取り出し、
    SetData内に self.BoneLengths というカスタムなパラメータ を作成して接続します。



     そうしたら、その下の、パーティクルの2点間から回転値を求めた部分 ↓ に、
    今度は、ツールタブの Math > Vector > Get Distance Between っていう文字通りの 間の距離を求めるノードに接続して 距離を取得します。
    それを、Set in Array を使って SetData の self.BoneLengths に接続します。



     これで、データは用意できたので、
    各ボーンについている ICETree の方に、骨の長さのデータを取得して、それが反映するようにします。
    GetDataで PointCloud から Model.PointCloud.BoneLengths から ボーンの長さデータを取得し、
    Select in Array を使って ボーン自身の 長さ this.length に SetData します。



    動かしてみましょう。

     

       Simulation_ICETree の方に Force > WindForce で風を設定すれば
      紐や布のような動きになり、
      Gridの方を動かせば、蛇やくらげの触手のような動きになります。

      Constraint_ICETree の実寸全体図です。
      お次は、Strand を利用した より複雑なスプリング の話になります。








位置データとしてのストランド

 Strand の利用1
      さて、ここからは中級以上です。ここまで追ってきているなら大丈夫でしょう。
    既に説明している部分が省きますよ。

     パーティクルの一種 Strand にシミュレーションを設定し、骨をそれに拘束することによって動きを得ようとする試みです。
    途中、いくつもの組まれたコンパウンドが出てきます。当然それらはデフォルトでは無いノードなので、 あれ?そんなん無いよ・・が出てきます。

     まずは、以下のものを用意します。



     ・骨の階層構造、
     ・制御用(マニピュレーター)の短形波表示のNull階層構造 
    の両方をModel (上記図では bone04 ) 以下に置き、その中に pointcloud があるとします。
    ボーンにはおなじみの ICEBoneParams カスタムパラメーターが設定されていて、BoneID番号が付随しています。
    骨構造体のGroup と 制御用NullのGroup を作成しておきます。


     
      pointcloud に設定されている ICETree も3箇所もあるので ↑、下から順に説明します。


位置データとしてのストランド

 PreSimulation_ICETree
     一番下に設定したICETreeです。ここでは基本的な Strand や ダイナミクス など初期設定をしています。
    ノードだけ見ると一見簡単そうに見えますが、 ”そんな名前のノードは存在しない ↓ ”  はずです。



     のっけから CreateBasicStrand は作成されたコンパウンドです。
    それに接続されているのは、一番上のボーンである  bone01 のグローバルの位置と回転値から Strand が発生されています。
     CreateBasicStrand は Particles タブ > Strands >  Create Strands が 元 になっています。
    まずは、この Create Strands をちゃんと動かす設定の説明から・・・・・。

     *---* ここから Create Strands の試し *---*

      こういった 直ぐに動かないものは、
    そのコンパウンドの中身を見て、なんのデータが不足して 真っ赤 になっているのか調べるところから始めます。

     Model の中に Strand を発生させる ポリゴンのGrid を作成して 下向きにし、 pointcloud を作ってICETreeを設定します。
    その Grid のグローバル移動値 を得ておいて、Particles タブ > Strands >  Create Strands を取り出します。



     ここは こしょっと  ずる なんですが、答えが先に解っていて、
    発生源のグローバル位置データを ツール タブ > Point Cloud >  Add Point  を使って接続してしまいます。



     でも、まだ真っ赤です。 CreateStrand コンパウンドの中身を見ると、赤や黄色で いっぱい です。
    で、上から順に見ていくと、最初に 真っ赤 なのが、パーティクルの Self.Orientation 、つまり自分の回転値が得ていないと気が付きます。



     なので、発生源のGridから その回転値を Self.Orientation として 接続してあげます。↓
    すると、いきなり線が描画されます。セグメントの数を  、 長さを  としておきます。
    でも、まだ 真っ赤 です。また、中を見てみます。



     上から見て行って、次に 真っ赤 のが、GetParticleSize で 、なんだよ 己の大きさ Self.Size も解んないないのかよ ってことで・・



     SetDataで Size を設定してあげます。↓すると、大きさが反映されて表示されます。
    でも、まだ 真っ赤 です、なに? って中身を見ると、



      すると、今度は色だってわかります、色はいいやと思って、あとで削除していますが、
    とりあえずここで色を反映させると、こうなります。



     Particle タブ > Setters > SetParticleColor  を接続します。↓
    これでようやく 真っ赤 が全部なくなりました。



     *---* ここまでが Create Strands の試し *---*

     このような設定を済ませたものが Create Basic Strand です。
    が、色指定の部分はざっくり消去、追加で self.strandsegmentlength self.strandUValues とういう値を取得しています。



     Build Strand Transforms は骨のように X軸が長さ軸になるように回転させています。実はこれもコンパウンドです。



    self.StrandOrientation に  ツールタブ > Conversion > Euler to Rotation で回転値にした Z軸値90度を足し、
    self.StrandPosition は Self.PointPosition からの配列を位置データとして
    SRT to Matrix でグローバル値にして self.StrandTransform にまとめています。
     スケール値は 真っ赤 で使用していません。
     この ツールタブ内の > Execution > First Valid (最初の有効な入力) って面白くって、"最初の正しい値を使う" というノードらしいのです。
    つまり、いつもは使ってないので真っ赤なんですが、その場合2個目に設定している値 ここでは X= 1、Y=1、Z=1 を使用します。
    つまりつまり、いつも 何もしなくてもスケール値は 1,1,1、 なんです。(でも、何かスケール値を入れると、そちらを使いますと・・)

    このコンパウンドが Create Basic Strand です >> Create Basic Strand
    --

     最初の図に戻って、次は Shape Strand with Manipulators ですが、これもやっかいなコンパウンドです。
    やっていることは Strand を Group指定した制御用のNullで 移動や回転を設定出来るように設定しています。



     中身を見て、一番右側の最後を見ると、self.StrandPosition を SetData していると解り、
    制御用のNullグループから得た グローバルの移動値と回転値から作り出してる、と気付きます。



    Pop from Array(配列からのポップ) は 一番最後の 配列 (Array値) つまり 一番下の Nullの位置
    Push on Array(配列でのプッシュ)  は 新しい 配列 (Array値) を作成、
    Remove from Array(配列からの削除)は "それぞれ-1ずつシフトされます"、つまり、一番上のNulの位置は 捨てています。
    何やってるかって言うと、並んでいるNullの位置の前後から、その位置と回転値を 配列 (Array値) 化して self.StrandPosition というデータを作成しています。
     ここは、2段目に小さく接続している Align Strand Segments も一緒になっていて、これもコンパウンドです。中と覗きます。

     

     すると 注釈が書いてあります。
    We subtract ajacent items in the array to find the vectors that go between the items in the array.
    ”我々は制御用Null間のベクトル(方向)を設定したっす”、と書いてあります。 つまり、ここでは回転値を計算しています。
     GetParticlePosition は Strandの根元の位置です。Insert in Array(配列への挿入) でさっき削除した根元の位置を追加しただけ、
    で、Pop from Array で 一番下の削除して、さっき求めた StrandPositionと 1個ずれるので、
    その差 Subtract を 例の "2点間から回転値を求める” IncrimentRotationWith2Vectors に接続しています (前頁参照)
    その結果 Self.StrandOrientation と self.StrandUpVector を求めています。

     つまり Shape Strand with Manipulators コンパウンドは、制御用のNullの影響から来る、
    新しい 位置;StrandPosition と 回転値;StrandOrientation を作り出しています。
    このコンパウンドが Shape Strand with Manipulators です >> ShapeStrandwithManipulators

       この部分 ↑、” 配列から 位置データと そこから導き出した回転値を求める ” というのは、良くあるパターンなので、
      覚えておくと、きっと何かの時に役に立ちます・・・・、きっと♪

    --

     最初の図に戻って、次最後の Init Strand Dynamics もコンパウンドです。
    Particle タブ > Strand Dynamics >  Init Strand Dynamics で、ダイナミクスに必要なものを準備してくれてます。
    このコンパウンドはデフォルトであるはずです。念の為 Init Strand Dynamics.1.1 です >> InitStrandDynamics_1_1



     CreateStrand ノードを使用している後では、
    必要とするパラメーター (self.StrandCount,Self.StrandLength、Self.StrandPosition、Self.StrandOrientation)は揃っているので 
    設定はうまくいくはずです。

     お疲れさん、ここまでが 最初の PreSimulation_ICETree でした。

位置データとしてのストランド
 
 Simulstion_ICETree
     2番目に設定したICETreeです。ここではいよいよダイナミクスを作成しています。
    Force を使っていることから解るように、通常のパーティクルのようにForceを接続できる StrandDynamicsFramework を使用しています。
     真っ赤 なのは、コリジョンとして設定している Shpere がシーン内から外してあるからで、複数のオブジェクトを設定できます。



     ここでは Strand にダイナミクスを設定して、シミュレーションを実行していきます。

    また上から順に見ていきましょう。

    ---

     Calc Local Rotation from Manipulators は、制御用のNullのグループから 各Nullの回転値を計算しています。
    これはこのまま、こうすれば配列からローカルの回転値が得られるのか・・ と公式のように応用してしまいましょう。
    最終的に Self.StrandLocalOrientation という変数に格納されています。



    このコンパウンド作れそうですが Calc Local Rotation from Manipulators です >> CalcLocalRotationfromManipulators

     お次の Constrain Particle to Object は、最初の制御用のNull に Strand の最初の部分をくっ付けています。
    これで一番上だけですが、制御用のNull で Strandを固定しています。
     やっていることは 最初の制御用Nullのグローバルの位置と回転値を Self.PointPosition、 Self.Orientation に代入しています。



     ここの大本命、StrandDynamicsFramework です。
    これ1つで はたり と下にたれ、バネの強さにもなり、衝突するものも指定できます。
    これはデフォルトで存在するもので、Particlesタブ内 > Strand Dynamics > StrandDynamicsFramework です。
    今は、数が 個、コリジョンのオフセットが 0.01、硬さが 0.12 になっています。



     接続しているフォースを上からみると・・・

     Strand Gravity Force は Y軸に -20 のベクトル値を設定しています。
    Particle タブ内 > Strand Dynamics > Strand Gravity Force があります。



     通常パーティクルで使う Gravity Forceと比べると 中身が違います。
    self.StrandCount は 前述の Create Basic Strands で NumSegment で 6個と書いた数字が入ります。
    つまり6個に それぞれ1個ずつ -20 の影響をさせています。



     お次の、Strand Drag Force は Particle タブ内 > Strand Dynamics > Strand Drag Force  です。
    強さ として 0.1 が設定されています。



     これも パーティクルで使う Drag Force とは全く異なり、中身を見ると、
    なにやら 前フレームの位置・・・・時間・・ああ、バネね と 前頁を思い出せば理解できます。ここはこのまま使いましょう。



     最後の、Null Controller Force は Particle タブ内 > Forces > Null Controller Force です。
    一番上の制御用Null の方向で 多少なりともなびく方向性を持たせたかっただけです。
    でも、このコンパウンドの中身を見るとたいへんです。 見なかったことにしましょう ♪♪♪




     最初の図 に戻って、
     一番下の Build Strand Transforms は、また 骨のように X軸が長さ軸になるように回転させて、
    中身も同じで  self.StrandTransform にまとめています。



     これでシミュレーションの設定は完了です。


       この状態で アニメーションを再生させると、
      既に びよよーん と  Strand だけが動き、
      制御用の Null  を動かすと 曲がってくれます。
       最後の ICETree では 
      このStrand の動きにボーンがくっ付いていくように設定しています。


位置データとしてのストランド
 
 Constraint_ICETree
     3番目に設定したICETreeです。ボーンを Strand の位置と回転値に合わせる 配列のデータ (BoneTransforms ) を用意しています。
    おや!! と気が付いた方は、そうもう見慣れて来ましたか? <ここまで追って来てくれた方ですね、ありがとうです。>
     ハイ、例のArrayを使ってボーンを設定する、IKやパーティクルの時と同じやり方です。
    ボーンのグループからその BoneID値 を取得して Set in Array で接続してください。
    後は、前頁や ICE IKの頁 を参照してください。
     終わりです。


     次は各ボーンに個別位置を設定した ICETree を設定します。

位置データとしてのストランド
 
 各ボーンのICETree
     さて最後です。個々のボーンに 以下のような ICETree を設定して Strand の位置にくっ付けています。
    これも あれ!! ・・・ですね。
     そう同じです。己の BoneID番号 を取得して、PointCloud に溜め込んだ BoneTransforms から Select in Array を使って取得し、
    それをグローバル値として自分に設定しています。



     お疲れ様です!! これで全て、設定完了です。
    あとは、そのシーンに合った都合の良いものに変えてください。



髪の毛
 
 コリジョンの設定
     さて 球や円柱を衝突物として設定して動かしてみます。ちゃんと反映されます。
    ただし、当たり判定している点は Size で大きさが変えられるものの大きくなると邪魔なので、
    レイヤ分けしておき、非表示やレンダリングしないレイヤに入れて置く と良いです。
     あと、当たり判定が球状なので滑ってしまい、スカートの当たり判定先が足のような丸いものにはむかないかもしれません。
    スカートは布的なICE処理の方が良いでしょう。



     ということで、髪の毛に使ってみました。 またキャラですみませんが・・・

     どのくらいの処理速度で動かせるのかも実験で、こんなにたくさん設定してみました。↓
    赤いポリゴンが頭を想定した当たり判定用のポリゴンで レンダリングされないレイヤに入っていて、Neckボーンの子供になっています。
    各Strandの位置を設定する制御用の Null も Neckボーンの子供になっていて、尚且つ 位置と方向のコンストレイントが付いています。


    その時の設定は 以下の通りです。


     動く方向とか、当たり判定のポリゴンの形状とか色々ありますが、こんな動きになりました。。


     影のレンダリング設定では、微妙な色のグラデーションを実現してみました。
    胸は 前頁の パーティクルのICEスプリングで揺らしてます。 (あまりやるとボインボインになってしまうので程ほどに・・)
         ギターは とあ さんです なせココに使う・・


     
     みなさんならもっとまともな所にでも使ってみてください。
    そして、そのシーンに合うようにカスタマイズをしていってください。


     追加情報 パーティクルの動きに追従していたオブジェクトの動きを取りたい場合、Plot を実行して通常のファンクションカーブにすることができます。
      ですが、そのオブジェクトに ICETree が設定されている状態ですと ファンクションカーブのデータで動きません。
       ICETreeを削除するか、無効にすると、ファンクションカーブの動きが有効になります。






     今回、結構ポリゴン数の多い、サブディビジョンサーフェイスのかかったポリゴンにICEを設定して動かしても
    再生しながら調整できる描画処理範囲内で動いています。
    Arrayを使ったICEの位置設定方法はかなりよいパフォーマンスなのではないでしょうか。




     という訳で、次回はなんと emPolygonizer 2.0 になりそうです。
      乞う、ご期待!!