チュートリアル -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 Operator)コード:

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

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

pCont.useTM = true

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

pCont.useAge = true

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

)

on Init pCont do
(

Init ハンドラは[スクリプト オペレータ](Script Operator)の初期化に使用します。パラメータ pCont にはパーティクル コンテナが含まれます。

global My_Atmospheric_Gizmos_01 = $SphereGizmo*

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

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

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

)

on Proceed pCont do
(

[スクリプト オペレータ](Script Operator)がパーティクル フローによって評価されるたびに、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 ()

関連事項