|
位置データとしてのパーティクル
Spring Force の利用6実は、前頁"SpringForceの利用3"の続きです。 各パーティクル間の距離は当然スプリングなので伸縮しますので、ボーンの長さもそれに応じて変化させたいところです。 COLOR="#ff0000" > 追加情報上図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します。 動かしてみましょう。 |
位置データとしてのストランド
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として接続してあげます。↓ すると、いきなり線が描画されます。セグメントの数を6、長さを5としておきます。 でも、まだ真っ赤です。また、中を見てみます。 上から見て行って、次に真っ赤のが、GetParticleSizeで、なんだよ己の大きさSelf.Sizeも解んないないのかよってことで・・ SetDataでSizeを設定してあげます。↓すると、大きさが反映されて表示されます。
すると、今度は色だってわかります、色はいいやと思って、あとで削除していますが、でも、まだ真っ赤です、なに?って中身を見ると、 とりあえずここで色を反映させると、こうなります。 Particleタブ > Setters > SetParticleColor を接続します。↓ これでようやく真っ赤が全部なくなりました。 *---* ここまでが Create Strands の試し *---* このような設定を済ませたものがCreate Basic Strandです。 が、色指定の部分はざっくり消去、追加でself.strandsegmentlengthself.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 です。 今は、数が5個、コリジョンのオフセットが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にまとめています。 これでシミュレーションの設定は完了です。
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になりそうです。 乞う、ご期待!!
|