CG・コンテンツ制作
  1. CG・コンテンツ制作トップ
  2. DAIKIN CG Channel
  3. UsersNotes
  4. ICE
  5. はじめての ICE Simulation その1 スプリング/コリジョン編;My First ICE Simulation No1 
SUITE USERS NOTES
Twitter 100Followers 記念
は・じ・め・て・の ICE Simulation その1
スプリング/コリジョン編
(My First ICE Simulation)
ICE_kine_01
ritaro_ml

プロローグ

今回は、より複雑な処理を実現させるICEによるシミュレーション機能についてに記述しようと思います。
ICE ビジュアル・プログラミングということで、ノードの組み合わせでパーティクルを制御できる訳ですが、
このパーティクルを”位置の集合体”として捉えると、
様々な位置データをICEのパーティクル・シミュレーションを使って制御する・・・という風に考えを変える事が出来ます。
ICEのパーティクルには、フォースやRBD(リジッド・ボディー・ダイナミクス;物理計算)などたくさんの制御方法が用意されているので ICE機能をうまく使えば位置データとして色々と処理することが可能となってきます。おもしろそうでしょ♪♪

ICE Treeを付ける場所も取得 > プリミティブ > ポイントクラウド > 空から作成されるpointcloudに設定します。
pointcloud に付けたICETreeは、実はシミュレーション・コンストラクション・モード以下に作成されている事に気付きます。
ICE_sim_01
もう一つ覚えておくべき事は、このpointcloudに付けたICETreeでないと利用出来ないICEノードもあるということです。(パーティクル制御だから・・)
その代表的なものに、Strands(ストランド)なんかがあります。発生位置から連続した線を計算(描画)します。

 >> 詳しくは、Softimageのユーザーガイドの Create Strands(ストランドの作成)項目サンプルシーン Strand_Dynamics_Hair.scn参照

この分野でのICE技術の利用はたいへん明るい未来が約束されており、
アイディア次第では アニメーション や Rig や モーション など様々なナイスな制御方法を生む事間違いなし!!、の技術です。

さー、ICEのスプリングやコリジョンの制御方法を学び、 位置データ制御をICEで行う際の基礎知識を習得しちゃいましょう!!

1) 位置データとしてのパーティクル
 > Spring Force の利用1
 > Spring Force の利用2
 > Spring Force の応用例;アホ毛
 > コリジョンを簡単に付ける例;アホ毛
 > Spring Force の利用3
 > ICEノード機能の探求のコツ
 > Spring Force の利用4
 > Spring Force の利用5

パソコンのスペック WindowsXP SP3、Intel Core2Duo 3G、RAM; 3G、NVIDIA Quadro FX1700



位置データとしてのパーティクル
ここからの幾つかのサンプル・シーンのデータ提供は;PSYOP Todd Akita さんからのものです。
Thank you Todd_San !!
同様の解説をしているムービーも存在しますが、この記事では更なる探求や応用例を紹介しています、それにココはやっぱ日本語だしね。

Spring Force の利用1
確か、この話をする時に最初に解説してもらったのが、フックの法則(英: Hooke's law)でした。(弾性の法則)

F=-kx
F;ばねによる反力 ;ニュートン
k;ばね定数と呼ばれる定数各ばね固有の値、ばねの強さ;ニュートン毎メートル
x;つる巻きばねの何もしてない状態の長さから伸び/縮みした分の距離;メートル

だとさ。つまり、バネ定数Kと伸縮する距離xを設定することでバネらしい動きを再現できる、ということでした。

では、まずは簡単なバネっぽい動きをするパーティクルの作成から始まります。
ICE_sim_02
PointCloudにICEシミュレーションのICETreeを作成し、
パーティクルのタスク内 Emitters  > Emit from Surfaceを取り出して、
GetGridでグリッドを発生場所(Emitter1)として接続します。
Emit from Surface内の項目では、
レートの種類を[パーティクルの総数] にし、パーティクルの発生数を [10] 個とし、速度を限りなく [0] に近い数値(0.3)を設定しています。
0にするとシーン再生時に全く動かなくなりますので、その方が良い場合もあります。Shape は見やすく為にSpereにしています。
Getters > Get Partivle Emit Locationで発生したパーティクルの位置を取得し、そのPositionをSpringForceに接続します.
SpringForceのノードでバネ定数Kとしての値を10としています。

このSpringForceコンパウンドの中身は、下図のようになっています。(発生地点と現在の位置を割った距離にK値を掛けた位置)
簡単なものですが、たくさん使いそうでしたらコンパウンド化して登録しておくと便利です。
 >> 
Spring Force.xsicompound
ICE_sim_03
Forces > Drag Forceと共に、Forces > Add Forces に接続します。
Drag Forceはつまり減衰値になります。ここを0に設定するとずーーーと上下にバウンドしたままになります。
最後はツール > Simulation > SimulateParticlesを一番下の最後のPortに接続します。これが無いとパーティクルが生まれません。

これで設定が完了していますので、シーンをプレイバック状態にして(ループモードにすると良いです)、Gridを動かしてみると、10個のパーティクルがぼよよーんと追従して来ます。
Spring K とStrenth の値を変更することで色々な動きに変化します。

バネらしい動きとは、つまりこの”減衰度合いをうまくコンロトールすること”になります。
そこで、この減衰する部分のノードを更に追求したのが次の例です。



Spring Forceの利用2
さー、ぐーんとノードが増えて来ましたが、前半は同じです。
改良されているのは、減衰部分のSpringDamperForceノード以下です。
ICE_sim_04
最初の例で利用しているデフォルトで存在するDrag Forceの中身を見ると、実は結構複雑なのです。
ここでのSpringDamperForceというコンパウンドの中身はたったこれだけです。
ICE_sim_05
VelAにはGetDataで self.pointvelocity の値を接続しています。
パーティクル・タスク内の Getters>GetParticleVelocity でも同じです。パーティクルの速度の取得だと解ります。
次は少し長いですね。
GetDataで Self.EmitLocationで放出ロケーションを取得して、
ツール内> DataAccess> GetDataAtPreviousFrameを取り出してpointpositionを取得しています。
これは前フレームでの位置、下は現在の位置を取得して
2つの入力値の差(減算値)にツール内 > DataAccess >  SimulationStep 数を掛けています。その値がVelBに来ています。
シミュレーションのステップとは1フレームの長さを秒単位で出力したもので、
フレーム数と秒数を変換する場合、またはフレーム単位で表された属性と秒単位で表された属性を変換するとヘルプに書いてあります。
Spring kd には 1 が入っています。
つまり全体では秒単位距離を速度で割った値に定数を掛けたということらしい。
結果、このSpringkdの値を小さくすると、バネの振動が収まる時間が長くなるという風に制御されました。(減衰値なので、値が大きいとはやくおさまると・・)
Springkd の値を0.5にしてGridを動かすと、かなりプルンプルン♪な動きになります。楽しい!!



Spring Force の応用例;アホ毛
日本文化(?)らしく、このSpring Forceから作成されたバネの動きをキャラクターのアホ毛に適応する例を紹介します。
アホ毛とは、キャラクターの頭から数本ピョンと突出た毛のこと、
英語ではFrizzって書いてあるが本当に通じるのか?どっちかって言うとそれは縮れっ毛?英語に出来ないからこそ日本文化なり。

以下に記述している点を知っておくと、ノードを接続できなかった時に「はた!!」と気付く事多いです。
それはパーティクルの位置データをポリゴンやNull等オブジェクトのグローバル値に直接つなげようとした時に起こります。
パーティクルのPointPositionはマルチポイントのデータ(1個しか放出していなくても)なので直付けできないのです。
白枠の部分がその設定です。
では詳しく見てみましょう。 あ、パーティクルの総発生数は1個になっています。

まずは”頭”を想定したSphereの子供にボーン構造を作成し、
同じく発生源であるGridを小さくしてSphereの子供にし、レンダリングされないようにVisibilityを変更し、ボーンのエフェクターの位置に設定しました。
Gridのセンターは”頭”を想定したSphereの位置にあります。
ICE_sim_06
ICETreeの白枠の設定は、GetData でエフェクターのグローバル値を取得し、Matrix to SRT でSRTを分けておきます。
ICE_sim_07
ここ重要!!GetDataでselfとだけ記入し、それをツール内 > Conversion>ID to Location ノードのGeomertyに接続します。
発生したパーティクルは、たとえ1つだったとしでもそのPointPositionは複数の値用のデータになっています。
発生させた最初のパーティクルのID値は0だと解っています。
つまり、ここの設定は、己の見てID=0のパーティクルのLocationを取得して、パーティクル1個の値をGetします。
[値の表示]をすると、ちゃんとID=0のパーティクルのグローバル値が表示されます。
あとは簡単ですね。その値をエフェクターのグローバル値に代入してやります。

仮にキャラに適応してみました。再生しつつ、あるいは画面Captureでムービーを見つつ、動きの調整をしていきます。
ポリゴン数の多さにも関わらず意外に軽く動きます。調整すると大きい数値(バネ定数)になりました。
設定としては、Headの子供としてスケールを小さくした発生源であるGridを置き、パーティクルのSizeを0にしています。
Massサイズはそのままが良いです、0にすると吹っ飛んでしまいます。
ICE_sim_08
ということで、久しぶりにキャラのアニメになりました。
髪の毛のゆれを手付けのアニメーションで無いはじめての例になりました。胸やリボンや後ろ襟などたくさんの利用が考えられます。





コリジョンを簡単に付ける例;アホ毛
さて、その次に、この位置として使うパーティクルにコリジョン(衝突判定)を付けるには、すごい楽な方法があります。
ICETreeのPortの最後に接続しているSimulateParticleをSimulateRigidBodiesにしてしまうのです。
その中のOcstracle(衝突するもの)にポリゴンのジオメトリーを接続してしまいます。
今度は、パーティクルのサイズで衝突を判定するので大きさが必要なのですが、
PointCloud自身にマテリアルを設定し、ハイライト無しのアルファーを設定して抜いてしまえば、
パーティクル自身をレンダリングしないようにできます。
ICE_sim_09
次の例では、複数のパーティクルの動作制御になってきます。



Spring Force の利用3
さて、これも前例の続きなので、右側半分はもう解説しています。
この動きは、10個のパーティクルが発生し、最初のが箱表示になっているNullにくっつき、
あとのはID番号順に次々と列を作って整列するするようという風になっています。
逆に言うと、Nullを動かすと、次々とパーティクルが追従して来るので蛇みたいなんですが、
スプリング制御で動いているので、パーティクル同士の間が大きくなると速度を速めて狭め、間がつまると動きがゆっくりになります。
ここにも知っておくべき項目がありますので解説してみましょう。
ICE_sim_10
これ↓、面白い設定方法ですね。解りましたか・・・。パーティクルはマルチのデータです。
己のIDをGetDataしていくのですが、最初のパーティクルは0と=なので、下行って、
Nullのグローバル位置データをGetDataしてそれをパーティクルの位置データとし、
それ以降のID は当然0じゃ無いので、なにもしない。ですって。
つまり、一番最初のパーティクルだけにNull位置データを渡したかったのですね。
ICE_sim_11
お次は、もっと不可思議、己のID値の下の1は 列数になるんです。
ID値から得たPointPositionをそのままSpringForceにつないでしまうとみんなNullの位置になってしまうところを、
間に空間のベクトル値(GetPosition の後のSubtract の Second につないでいる"Spacer"Vectorを入れ込んでいて、その分 間が開いて整列します。
ICE_sim_12
仮に、最初の数値が 3、SpaceVectorにZ=2だとこうなります。
ICE_sim_13



既存サンプルとしてはここまでのものでした。

ここからこれを元にボーンを組み込んでコリジョンまで対応させてみましょう。
どんな風に既存サンプル技術を目的とするような動きに応用させるのかの例としてみて見てください。面白い技たくさんあります。
ICE_sim_14
↑こんな感じが目標です↑
では、行きます。
まずは、ICETreeノードを2つに分けることを考えておきます。
1つは上記のパーティクルを生むICETreeをSimulation_ICETreeと名前を付け、
もう1つのパーティクルにオブジェクトをくっ付けるICETreeを Constraint_ICETreeを命名したとします。
パーティクルの発生源がGridなので、そこからの位置で制御するように変更しました。
Nullからの位置データではなくでGridからの位置データをIf ノード下にSetDataで渡します。
パーティクルの発生も、[法線方向] とし(つまり、今このGridは下が正面)、発生個数を6個、Speedに5を入れて速く整列するようにしました。
ICE_sim_15
CEDEC2010では、「”重力”という要素を考えてアニメーションを付ける」、
ということがなんとなくのあちこちから聞こえて来たキーワードの1つだったので、
ココに重力フォースを追加してみました。
と言っても、中身を見るとYに-9が入っているだけの 3DVector だって解ります。
追加でVectorの方向を他のオブジェクトからの回転値で制御できるノードとしてRotateVectorを紹介しておきます。
その結果を[値の表示]で表示をVectorsにするとGridの回転値でVectorの方向が変化しているのが見てとれます。
とっても便利なノードなので覚えておいてください。
この例ではスプリングに制御されてしまうので、大幅に方向を変えることができませんが、少し膨らみを持たせることが出来ます。
/ICE_sim_16
残りの設定で変更したのは、Springを強くして30、間の距離を”Spacer Vector”に2(1.8は試し数字でした)、減衰用SpringDampForceに2を入れてます。
ICE_sim_17
では次はボーンをパーティクルにくっ付ける方法の考察です。
まずは、6個のパーティクルに対して、取得 > プリミティブ > インプリシット > ボーンから5つのボーンを用意し、
それらが内包するGroupを作成しておきます。
ICE_sim_18
上記で、1つのパーティクルに対して1つのオブジェクトの位置を渡す方法で5つのボーンをくっ付けるとこんな感じになります。↓
なんか、うーんな感じしませんか?あと、ICEのIKで説明した通り、SetDataを大量に設定することは処理的に効率的では無いと・・・
ICE_sim_19
また、各ボーンには回転値が考慮されてないので、皆ストレートに下向きのボーンになってつながっています。
これはパーティクルの位置に置いてあるだけなので当然ですし、元々階層構造のボーンでも無いからですね。ここにも工夫してみましょう。
そこで、そうです、あれです。ICEIKで説明したSet in Array を使った高速化方法を利用するのです。
出し惜しみをしてもしょうがないので、先にそのICETree構造を見せて解説していきます。

考え方の大前提として、ここもマルチポイントのデータですので、1つ設定で6個全部のデータを処理します。
PointCloudに2個目のICETreeを設定しConstraint_ICETreeを命名します。
値を格納しておく箱として4x4IndentityBuildArrayFromConstantから得たデータを
SetDataで BoneTransformsという新しいパラメータを作成して、そこに接続し(流し込み)ます。
ICE_sim_20
ボーンのグループbone_groupをExplorerからD&DでノードをICETree上に持って来て、
そこからGetDataでICEBoneParamsのBoneID を取得します。(この解説はICE IK を参照、グループを選択してスクリプトを実行すれば作れます)
そのBoneID値をSet in Array の Index に渡すと共に、下のID to LocationのID値にも接続します。
これでBoneID値とその時のパーティクルIDから判別する位置データを同時に設定出来たことになります。
(つまり、BoneのIC値が0の時、パーティクルのID値が0の時の位置データが設定されます)

お次が、骨の回転値です。
こう考えると簡単ですね、二点間の位置データから方向Vectorを得られればと。
これにはIncrement Rotation with 2 Vectorsを使います。
ここでの使い方は、Increment Rotation with 2 Vectorsの最初の Rotation にはGridの回転値を入力しておいて、
パーティクルのIDの位置データとそのID値に1足した位置データ(つまり例えばID値0と1)
の位置の違いをIncrement Rotation with 2 VectorsToVectorにつなぐと回転値を計算してくれます。
ICE_sim_21


ICEノード機能の探求のコツ
上図右下に使ってないノードが2つあります。↑
完成したノードのつなぎ方にたどり着く前に、その機能について探っていた時に見ていたコンパウンドなのです。
コンパウンドは複数のICEノードを組み合わせて機能を達成させている実例になっています。
つまり、その中身を見てどんなノードをどういう風に組んでいるのかを見ることによって、
各ノードの使い方を知ることができるのです。

ちょっと調べ方の例として、今回はこんな風に探りました。

例えば、2点間のコンストレイントなんて機能のコンパウンドがあれば、
きっと2点の位置と回転値から導き出しているに違いない・・・と考えます。
すると、Kinematics > ConstrainBetween2Pointsを探せ出せます。
このコンパウンドの中身を見ると・・・
なんだInterpolate Pose Between 2 Positionsというコンパウンドが
2つのグローバル位置をブレンドしてるんだ・・と気付きます。
ICE_sim_22
このInterpolate Pose Between 2 Positionsもコンパウンドなので、更に中身を見ると・・・
おお、あったあった、
・回転値を最初につないだものをそのまま使うか、
・Increment Rotation with 2 Vectorsで得た2点間から計算した回転値を使用するか、
IFノードで選択し、
位置は二点間から計算した結果を移動値としていて、
最後にSRT to Matrix でグローバル値に結合にして出力している・・・とわかります。とっても、便利ですね。
ICE_sim_23
こんな風に追うと使い方が解るんです。
普通はここまでで、これを便利に応用すれば良いかと思います。


-*-*-*-*-*-
でもね、本当はもっと複雑なのです。ここからはプログラマーさん向けです。
実は、Increment Rotation with 2 Vectorsもコンパウンドなので、更に中身を見ると・・・
ICE_sim_24
ちゃんと回転値をクォータニオン変換して計算してから回転値に戻しており、
なにやらRotateArcなるものが介在していると・・・・知ります。これもコンパウンドです。
これにはコメントも付いていて
Taken from the Game Programming Gems article 'The shortest Arc Quaternion' by Stan Melaxとあります。
上記書籍にてこのクォータニオンの計算について日本語では最小弧クォータニオンと書かれています。
このRotationArc()という関数は、2つのベクトル V0 とV1からq*v0==v1 を満たす クォータニオン qを計算するものです。
quaternion RotationArt(vector3 v0,vector3 v1)以下がICETreeのノードで実現しているんだと知ります。
ICE_sim_25
上のCrossProduct で軸計算でVector、DotProduct で角度計算で数値、Scalor to Quaternionなんてデフォルトでノードがあります。
プログラマーさんで、クォータニオン計算をICEで実装しようとする方はここをぜひ参考にして欲しいところです。
ここでのノード使用例でも、上図Vector1からの値が入力されて計算結果であるRotation値を使用していることになります。


さて、話を戻します。
で、コンストレイントに使用するBoneTransforms値をID値と合わせて準備できました。
今度は各ボーンに己に持っているID値から対応する位置データを取得して自分のグローバル値とする部分です。
これは、もう ICE IK のところで既に説明しているのです。
ICE_sim_26
己の BoneID値 を GetData し、それを SelectArrayの Index に接続します。
PointCloudから集めた BoneTransforms値を GetData し、SelectArray の Array に接続します。
そこから得た位置データをその骨のフローバル値としてSetData します。
これを各ボーンに設定するのですが、黄色い枠内はいつも同じで、何も変化がありませんので、
コンパウンド化してくっ付けている例がICE IK のところで書いてあります。
どうでしょうか?ちゃんと骨が動いていますでしょうか?

最後は、ちょっと安直ですが、
SimulateParticlesをSimulateRigidBodiesに変えて球を障害物として設定してみました。
くっつき度Elasticity1 は0にしてあります。
ICE_sim_27
動かしてみるとこんな感じになります。
伸びたり縮んだりする例になるので、紐とかゴムとかの付属物のアニメーションに良いかも知れませんね。
あるいは、思いっきりピーンとさせて文字通りバネに使用するかです。




Spring Force の利用4
これも面白いSpring利用例になります。
下図は、エンベロープの付いているポリゴンとそれの複製に ICE を設定し、
エンベロープのアニメーションが止まっても、ICEの方がびよよーんと動きが残るようになっています。
アニメーションの時は、エンベロープの付いているオブジェクトを非表示にしておくというわけです。
ICE_sim_30
解説としては、エンベロープの付いている方のポリゴンのPointPositionをGetDateで取得し、
Conversion > Switch Contextという珍しいノードを使用してSpringForceに接続します。
このSwitch Context(コンテキストの切り替え)は、2つのオブジェクトが全く同じジオメトリ構造同士でないと動作しないのですが、
同じであれば、位置のブレンド等入れ替えが出来るノードのようです。
で、Switch Contextで頂点位置のデータを受け渡したら、SpingForce で動きが計算され、びよよーんが残ると。
減衰用のDragは前述の少し変えたもので、
Getters>GetParticleVelocityでパーティクルの速度
Math > Basic > Negate否定演算(符号を反転)、DataAccess> SimulationStep は1フレームの長さを秒単位で出力しています。
つまり秒単位あたりの距離となっています。
ICE_sim_31
ポリゴン自体のぼよよーん動きの例としては、トランポリンや太鼓、破壊される破片がブヨブヨしているなどの使い道がありそうです。

複製元の頂点位置データを取ってきているだけ・・なので、きっと ShapeAnimationもOKなはずです。
実際に実験してみましょう、トランポリンで。
Softimageの ShapeManager はとっても簡単便利、元の形と、それの真ん中を引っ張った形を登録すれば、
勝手にスライダーができるので、たった1フレームで元に戻るというアニメーションをそのスライダーのキーアニメーションで作成します。
ICE_sim_32
あとは、上記 ICE の Sping を何もアニメーション設定のしていない複製したポリゴンの方に設定し、
Shapeアニメーションの付いている方は非表示にします。
ICE_sim_33
ということで、ジオメトリーが同じということの典型である ShapeAnimationを使って
ICE によるSpring設定が出来ることが解りました。




Spring Force の利用5
さて最後です。
これは純粋にパーティクルの話です。
発生した地点を得て、定数をTurbulize(乱れ値)した値でSpingForce を設定しているので、動きの延滞がおもしろい動きをするよ、というものです。
減衰値の方にもParticleタスク > Modifiers>TurbulizeAroundValueがついています。
30000個もパーティクル発生していますが、意外と動いて見れるものです。
ICE_sim_40
Particleタスク > Modifiers>TurbulizeAroundValueの設定値です。
ICE_sim_41
これはもうレンダリングを想定した設定で、ジェリー状の付着物、まとわり付く煙など考えてみましょう。

ICEによるシミュレーションはいかがでしたでしょうか?位置の処理にICEのシミュレーションを使うということが理解できたでしょうか?
実は全く別のICE設定のSpringも書く予定でしたが、これだけでもお腹いっぱいな感じです。
そちらは更に設定が高度なのでじっくり説明したい・・・・ので、次回としましょう。

という訳で、次回も ICE Simulationネタになりそうです。
乞う、ご期待!!
戻る 次へ

お気軽にお問い合わせください

Daikin CG News お申し込み

CGクリエイター向けのセミナー・イベントやキャンペーン、製品情報をメールマガジンでお届けします。(登録無料)

Twitter

ページの先頭へ