|
位置データとしてのパーティクル
ここからの幾つかのサンプル・シーンのデータ提供は;PSYOP Todd Akita さんからのものです。
Spring Force の利用1Thank you Todd_San !! 同様の解説をしているムービーも存在しますが、この記事では更なる探求や応用例を紹介しています、それにココはやっぱ日本語だしね。 確か、この話をする時に最初に解説してもらったのが、フックの法則(英: Hooke's law)でした。(弾性の法則)
だとさ。つまり、バネ定数Kと伸縮する距離xを設定することでバネらしい動きを再現できる、ということでした。 では、まずは簡単なバネっぽい動きをするパーティクルの作成から始まります。 ![]() パーティクルのタスク内 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 ![]() Drag Forceはつまり減衰値になります。ここを0に設定するとずーーーと上下にバウンドしたままになります。 最後はツール > Simulation > SimulateParticlesを一番下の最後のPortに接続します。これが無いとパーティクルが生まれません。 これで設定が完了していますので、シーンをプレイバック状態にして(ループモードにすると良いです)、Gridを動かしてみると、10個のパーティクルがぼよよーんと追従して来ます。 Spring K とStrenth の値を変更することで色々な動きに変化します。 バネらしい動きとは、つまりこの”減衰度合いをうまくコンロトールすること”になります。 そこで、この減衰する部分のノードを更に追求したのが次の例です。 Spring Forceの利用2 さー、ぐーんとノードが増えて来ましたが、前半は同じです。 改良されているのは、減衰部分のSpringDamperForceノード以下です。 最初の例で利用しているデフォルトで存在するDrag Forceの中身を見ると、実は結構複雑なのです。 ここでのSpringDamperForceというコンパウンドの中身はたったこれだけです。 ![]() パーティクル・タスク内の 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の位置にあります。 ![]() ![]() 発生したパーティクルは、たとえ1つだったとしでもそのPointPositionは複数の値用のデータになっています。 発生させた最初のパーティクルのID値は0だと解っています。 つまり、ここの設定は、己の見てID=0のパーティクルのLocationを取得して、パーティクル1個の値をGetします。 [値の表示]をすると、ちゃんとID=0のパーティクルのグローバル値が表示されます。 あとは簡単ですね。その値をエフェクターのグローバル値に代入してやります。 仮にキャラに適応してみました。再生しつつ、あるいは画面Captureでムービーを見つつ、動きの調整をしていきます。 ポリゴン数の多さにも関わらず意外に軽く動きます。調整すると大きい数値(バネ定数)になりました。 設定としては、Headの子供としてスケールを小さくした発生源であるGridを置き、パーティクルのSizeを0にしています。 Massサイズはそのままが良いです、0にすると吹っ飛んでしまいます。 ![]() 髪の毛のゆれを手付けのアニメーションで無いはじめての例になりました。胸やリボンや後ろ襟などたくさんの利用が考えられます。 コリジョンを簡単に付ける例;アホ毛 さて、その次に、この位置として使うパーティクルにコリジョン(衝突判定)を付けるには、すごい楽な方法があります。 ICETreeのPortの最後に接続しているSimulateParticleをSimulateRigidBodiesにしてしまうのです。 その中のOcstracle(衝突するもの)にポリゴンのジオメトリーを接続してしまいます。 今度は、パーティクルのサイズで衝突を判定するので大きさが必要なのですが、 PointCloud自身にマテリアルを設定し、ハイライト無しのアルファーを設定して抜いてしまえば、 パーティクル自身をレンダリングしないようにできます。 ![]() Spring Force の利用3 さて、これも前例の続きなので、右側半分はもう解説しています。 この動きは、10個のパーティクルが発生し、最初のが箱表示になっているNullにくっつき、 あとのはID番号順に次々と列を作って整列するするようという風になっています。 逆に言うと、Nullを動かすと、次々とパーティクルが追従して来るので蛇みたいなんですが、 スプリング制御で動いているので、パーティクル同士の間が大きくなると速度を速めて狭め、間がつまると動きがゆっくりになります。 ここにも知っておくべき項目がありますので解説してみましょう。 ![]() 己のIDをGetDataしていくのですが、最初のパーティクルは0と=なので、下行って、 Nullのグローバル位置データをGetDataしてそれをパーティクルの位置データとし、 それ以降のID は当然0じゃ無いので、なにもしない。ですって。 つまり、一番最初のパーティクルだけにNull位置データを渡したかったのですね。 ![]() ID値から得たPointPositionをそのままSpringForceにつないでしまうとみんなNullの位置になってしまうところを、 間に空間のベクトル値(GetPosition の後のSubtract の Second につないでいる"Spacer"Vector)を入れ込んでいて、その分 間が開いて整列します。 ![]() ![]() 既存サンプルとしてはここまでのものでした。 ここからこれを元にボーンを組み込んでコリジョンまで対応させてみましょう。 どんな風に既存サンプル技術を目的とするような動きに応用させるのかの例としてみて見てください。面白い技たくさんあります。 ![]() ↑こんな感じが目標です↑ まずは、ICETreeノードを2つに分けることを考えておきます。 1つは上記のパーティクルを生むICETreeをSimulation_ICETreeと名前を付け、 もう1つのパーティクルにオブジェクトをくっ付けるICETreeを Constraint_ICETreeを命名したとします。 パーティクルの発生源がGridなので、そこからの位置で制御するように変更しました。 Nullからの位置データではなくでGridからの位置データをIf ノード下にSetDataで渡します。 パーティクルの発生も、[法線方向] とし(つまり、今このGridは下が正面)、発生個数を6個、Speedに5を入れて速く整列するようにしました。 CEDEC2010では、「”重力”という要素を考えてアニメーションを付ける」、 ということがなんとなくのあちこちから聞こえて来たキーワードの1つだったので、 ココに重力フォースを追加してみました。 と言っても、中身を見るとYに-9が入っているだけの 3DVector だって解ります。 追加でVectorの方向を他のオブジェクトからの回転値で制御できるノードとしてRotateVectorを紹介しておきます。 その結果を[値の表示]で表示をVectorsにするとGridの回転値でVectorの方向が変化しているのが見てとれます。 とっても便利なノードなので覚えておいてください。 この例ではスプリングに制御されてしまうので、大幅に方向を変えることができませんが、少し膨らみを持たせることが出来ます。 ![]() ![]() まずは、6個のパーティクルに対して、取得 > プリミティブ > インプリシット > ボーンから5つのボーンを用意し、 それらが内包するGroupを作成しておきます。 ![]() なんか、うーんな感じしませんか?あと、ICEのIKで説明した通り、SetDataを大量に設定することは処理的に効率的では無いと・・・ ![]() これはパーティクルの位置に置いてあるだけなので当然ですし、元々階層構造のボーンでも無いからですね。ここにも工夫してみましょう。 そこで、そうです、あれです。ICEIKで説明したSet in Array を使った高速化方法を利用するのです。 出し惜しみをしてもしょうがないので、先にそのICETree構造を見せて解説していきます。 考え方の大前提として、ここもマルチポイントのデータですので、1つ設定で6個全部のデータを処理します。 PointCloudに2個目のICETreeを設定しConstraint_ICETreeを命名します。 値を格納しておく箱として4x4IndentityとBuildArrayFromConstantから得たデータを SetDataで BoneTransformsという新しいパラメータを作成して、そこに接続し(流し込み)ます。 ボーンのグループ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 VectorsのToVectorにつなぐと回転値を計算してくれます。
さて、話を戻します。 で、コンストレイントに使用するBoneTransforms値をID値と合わせて準備できました。 今度は各ボーンに己に持っているID値から対応する位置データを取得して自分のグローバル値とする部分です。 これは、もう ICE IK のところで既に説明しているのです。 ![]() PointCloudから集めた BoneTransforms値を GetData し、SelectArray の Array に接続します。 そこから得た位置データをその骨のフローバル値としてSetData します。 これを各ボーンに設定するのですが、黄色い枠内はいつも同じで、何も変化がありませんので、 コンパウンド化してくっ付けている例がICE IK のところで書いてあります。 どうでしょうか?ちゃんと骨が動いていますでしょうか? 最後は、ちょっと安直ですが、 SimulateParticlesをSimulateRigidBodiesに変えて球を障害物として設定してみました。 くっつき度Elasticity1 は0にしてあります。 ![]() 伸びたり縮んだりする例になるので、紐とかゴムとかの付属物のアニメーションに良いかも知れませんね。 あるいは、思いっきりピーンとさせて文字通りバネに使用するかです。 Spring Force の利用4 これも面白いSpring利用例になります。 下図は、エンベロープの付いているポリゴンとそれの複製に ICE を設定し、 エンベロープのアニメーションが止まっても、ICEの方がびよよーんと動きが残るようになっています。 アニメーションの時は、エンベロープの付いているオブジェクトを非表示にしておくというわけです。 ![]() Conversion > Switch Contextという珍しいノードを使用してSpringForceに接続します。 このSwitch Context(コンテキストの切り替え)は、2つのオブジェクトが全く同じジオメトリ構造同士でないと動作しないのですが、 同じであれば、位置のブレンド等入れ替えが出来るノードのようです。 で、Switch Contextで頂点位置のデータを受け渡したら、SpingForce で動きが計算され、びよよーんが残ると。 減衰用のDragは前述の少し変えたもので、 Getters>GetParticleVelocityでパーティクルの速度 Math > Basic > Negate否定演算(符号を反転)、DataAccess> SimulationStep は1フレームの長さを秒単位で出力しています。 つまり秒単位あたりの距離となっています。 ![]() 複製元の頂点位置データを取ってきているだけ・・なので、きっと ShapeAnimationもOKなはずです。 実際に実験してみましょう、トランポリンで。 Softimageの ShapeManager はとっても簡単便利、元の形と、それの真ん中を引っ張った形を登録すれば、 勝手にスライダーができるので、たった1フレームで元に戻るというアニメーションをそのスライダーのキーアニメーションで作成します。 ![]() Shapeアニメーションの付いている方は非表示にします。 ![]() ICE によるSpring設定が出来ることが解りました。 Spring Force の利用5 さて最後です。 これは純粋にパーティクルの話です。 発生した地点を得て、定数をTurbulize(乱れ値)した値でSpingForce を設定しているので、動きの延滞がおもしろい動きをするよ、というものです。 減衰値の方にもParticleタスク > Modifiers>TurbulizeAroundValueがついています。 30000個もパーティクル発生していますが、意外と動いて見れるものです。 Particleタスク > Modifiers>TurbulizeAroundValueの設定値です。 ![]() |
ICEによるシミュレーションはいかがでしたでしょうか?位置の処理にICEのシミュレーションを使うということが理解できたでしょうか? 実は全く別のICE設定のSpringも書く予定でしたが、これだけでもお腹いっぱいな感じです。 そちらは更に設定が高度なのでじっくり説明したい・・・・ので、次回としましょう。 |
という訳で、次回も ICE Simulationネタになりそうです。 乞う、ご期待!!
|