チュートリアル - ParticleFlow のパーティクル モーションのシーン オブジェクトへの転送

この簡単なチュートリアルでは、パーティクル フローを使用してシーン オブジェクトを動かす方法の基本について説明します。オブジェクトは、ライトからヘルパーおよびメッシュ オブジェクトまであらゆるオブジェクトが対象になります。

この例では、ファイヤ効果を割り当てた大量の周囲効果ギズモを動かして、ティーポットが湯気を立てる様子をシミュレートします。

全体の流れ: 設定

[作成] (Create)パネルで、[ヘルパー] (Helpers) > [環境効果の装置] (Atmospheric Apparatus) > [球体ギズモ] (Sphere Gizmo)に移動します。

任意の半径を持った SphereGizmo01 というオブジェクトを 1 つ作成します。

[Shift]キーを押しながらオブジェクトを移動して 29 と入力し、球体ギズモのコピー(インスタンスではありません)を 30 作成します。

[発生] (Birth)オペレータを使用して開始フレームから終了フレームまで 20.0 のレートでパーティクル を生成する パーティクル フローを作成します。

Speed オペレータを使用して、パーティクルを加速させます。多少の変動を与え、よりランダムな感じを出します。

表示をジオメトリに設定します。

[エージ テスト] (Age Test)を追加し、50 フレームを過ぎたらパーティクルを消滅させます。別のイベントの Delete オペレータにワイヤリングします。

さらに動きを出す場合は、フォースと風を追加します。

シーンが完璧に動作するように、[環境] (Environment)ダイアログ ボックスで[火の効果] (Fire Effect)を指定し、30 の球体ギズモすべてを割り当てます。思い通りの結果になるように、カラーの設定や密度などをいろいろ試してみます。

ティーポットを作成し、パーティクル フローを注ぎ口に位置づけて、蒸気が正しい場所から出るようにします。

Script オペレータのコード:

on ChannelsUsed pCont do
(
 pCont.useTM = true
 pCont.useAge = true
)

on Init pCont do
(
 global My_Atmospheric_Gizmos_01 = $SphereGizmo*
 My_Atmospheric_Gizmos_01.pos = [0,0,-100000]
)

on Proceed pCont do
(
 partcount = pCont.NumParticles()
 count = amin #(partcount, My_Atmospheric_Gizmos_01.count)
 for i in 1 to count do
 (
  pCont.particleIndex = i
  My_Atmospheric_Gizmos_01[i].transform = pCont.ParticleTM
  My_Atmospheric_Gizmos_01[i].radius = 10 + pCont.ParticleAge*2
 )
)

on Release pCont do ( )

結果:

ステップごとの解説

on ChannelsUsed pCont do
(

ChannelsUsed ハンドラは、Script オペレータが使用するチャネルを定義します。アクセスする必要のあるプロパティを指定せずに、パーティクル コンテナからパーティクル関連の値を取得したり、設定することはできません。このように、パーティクル フローは、Script オペレータにすべてのチャネルを与える必要はなく(パーティクル フローには任意の数のチャネルが存在します)、実際に必要となるチャネルだけを与えます。これによりメモリが節約されます。

パラメータ pCont にはパーティクル コンテナが含まれます。

pCont.useTM = true

パーティクルからシーン オブジェクトへの変換をすべてコピーしたいので、そのチャネルに対するアクセスが必要になります。

pCont.useAge = true

さらによい結果を得るためには、パーティクルのエージを読み取ってギズモの半径プロパティに割り当て、時間の経過に伴いギズモが拡大するようにします。

)

on Init pCont do
(

Init ハンドラは Script オペレータの初期化に使用します。パラメータ pCont にはパーティクル コンテナが含まれます。

global My_Atmospheric_Gizmos_01 = $SphereGizmo*

パーティクルが駆動するシーン オブジェクトの配列を入れるグローバル変数を定義します。この場合、共通の基本名を使用して、シーンからすべての SphereGizmo を収集します。

My_Atmospheric_Gizmos_01.pos = [0,0,-100000]

アニメーションの第 1 フレームのシーンからギズモを削除するには、カメラの視野から取り除きます。 ここでは、下の方に移動させます。

)

on Proceed pCont do
(

Script オペレータがパーティクル フローによって評価されるたびに、Proceed ハンドラが呼び出されます。ハンドラには、スクリプトの実際の本体が含まれています。パラメータ pContには、オペレータの適用先であるすべてのパーティクルを収めたパーティクル コンテナが含まれています。

partcount = pCont.NumParticles()

まず、現在のイベント内のパーティクルの数を読み込みます。イベント内のパーティクル数は 0 の場合も数百万の場合もあります。

count = amin #(partcount, My_Atmospheric_Gizmos_01.count)

次に、パーティクルの数を収集されたギズモの数と比べます。amin() 関数は、配列内の最小値を返します。

同じことを次のように表現できます。

if partcount < My_Atmospheric_Gizmos_01.count then
count = partcount
else
count = My_Atmospheric_Gizmos_01.count

見てわかるとおり、最初のコードの方が短いです。また、常に最小値を選び出すので、必要に応じて値の数が 2 つより多い場合でも使用することができます。

必要な理由

アニメーションの最初の方では、パーティクルの数が限られており、ギズモの数より少ないためです。しばらくたつと、パーティクルの数はギズモの数より多くなります。どちらの場合も、ギズモとパーティクルの「ペア」がほしいわけですが、パーティクルやギズモの一部は、アニメーションの特定部分においては対応するパートナーを持たない可能性があります。これらのオブジェクトの最小数を知っていれば、処理できるペアの数を得られます。

 for i in 1 to count do
(

シーン内でパーティクルとギズモのペアが可能な回数だけ、次のコードを繰り返します。

pCont.particleIndex = i

パーティクルからデータを読み込むには、それを現在のものにする必要があります。そのためには、現在のイベントの particleContainer の particleIndex プロパティ にインデックス i を割り当てます。その後、パーティクル関連の問い合わせや割り当ては i 番目のパーティクルだけに対して行われます。

My_Atmospheric_Gizmos_01[i].transform = pCont.ParticleTM

これで、現在の i 番目のパーティクルの変換行列を配列内の i 番目のギズモに割り当てることができます。上記の便利な amin テストのおかげで、i はパーティクルとギズモの数のどちらとも等しいか、それより少ないことが保証されます。

My_Atmospheric_Gizmos_01[i].radius = 10 + pCont.ParticleAge*2

最後に、i 番目のギズモの半径を、10 単位に i 番目のパーティクルのエージの倍を加えたものに変更します。10 はギズモの最小サイズです(particleAge が 0 の場合)。たとえばエージが 10 の場合、ギズモの半径は 30 単位になります。さまざまな値を試してみると、異なる湯気の動きが得られます。

)
)

on Release pCont do ()