仕事でXSIのパーティクルを使う機会があったので、ICEを使ってみた。
暫くパーティクルを使う機会が無さそうなので忘れてもいいようにメモ。
作り方なんてどうでもいいからダウンロードさせろや(#゚Д゚)クルァ! って人はConeEmitterダウンロード
最小のエミッター

エミッターに必要なノードは、AddPoint、SimulateParticles、
PointVelocityを設定するノードの3つ。
AddPointのPositions1に発生位置を、
SetDataコンパウンドでPointVelocityを設定してやれば1フレームに一つずつパーティクルを飛ばすエミッターが出来る。
PointVelocityはパーティクルを飛ばす方向とスピードを設定するベクトル。スピードはベクトルの大きさで設定する。
ノードを追加して、1フレームに一つずつポイントを追加して、原点から真上にスピード5でパーティクルを放出するエミッターにした。

@発生位置の設定を外に出した。こうすれば他のオブジェクトの位置などを参照して発生位置をコントロールできるようになる。
Aパーティクルの設定するコンパウンド。他のエミッターからコピってきた。
BPointVelocityの方向とスピードを分離させた。
本当は方向は正規化(ベクトルの大きさを1にすること)をした方が良いんだけど面倒なので省略した。
パーティクルの初期設定をする場合は、SetDataなどを使ってAddPointのOnCreationポートに繋げる。
Executeノードは後々コンパウンド化する時に便利なので追加した。
さらに追加して、パーティクル発生レートを設定する前段階。

SelectCaseはConditionポートの数値で処理を分岐させるノードで、
FilterIfEmittedはパーティクルが発生済みならパーティクルの発生を抑えるノードで、コレも他のエミッターからコピってきた。
SelectCaseのConditionに「1」が入力されているのでCase1の方が実行される。
なので最初のフレームにパーティクルが一つだけ発生するようになっている。
更に追加して、放射状にパーティクルを飛ばすコーンエミッターにした。
上で1に設定してあったSelectCaseのConditionを0に変更して毎フレームパーティクルが発生するようにしてある。


PointVelocityを設定する所にノードを追加した。
RandomRotationByConeで放射範囲を設定する。
しかしPointVelocityはベクター型でRandomRotationByConeの出力はローテーション型なのでデータ型を変換しなければならない。
上の図の一番目と二番目では、ローテーションからベクターへの変換方法が違うけど同じ結果が出る。
一番目はマトリックスに変換してから方向ベクトルを抜き出す方法で、
二番目は基準となる方向ベクトルをローテーションで回転させて方向ベクトルを取得している。
二番目の方が簡単で後々ツリーが複雑にならなそうなので今回はコッチを採用したけど、
マトリクスからベクターを取り出す方法はカーブに添わしてパーティクルを動かしたりとか色々応用が利くのでコレも載せてみた。
ついでなので一番目のマトリクスを使った方法も書いておく。コレは下のマトリクスの性質を利用して方向ベクトルを抜き出している。

緑の四角?で囲まれた3x3の部分は回転とスケールの情報を持っていて、一番上がX軸の向きと大きさ、二番目がY軸、
三番目がZ軸のオブジェクトの原点からのベクトルが入っていて、一番下の段にはオブジェクトの位置が入っている。
で、
基準の向きを真上(0,1,0)に設定してあるので3x3マトリクスの二段目を抜き出すとオブジェクトから見た真上の方向ベクトルになる。
逆に方向ベクトルがわかっていれば回転マトリクスを作ることが出来る。
エミッターの続き。さらにノード追加して、パーティクル発生レートを設定できるように。

AddPointのPositions1に繋がるところにノードを追加。
BuildArrayFromConstantノードは定数から配列をつくるノードで、
この配列の大きさでパーティクル発生レートを設定する。
Positionsポートにただのベクトルを設定するとフレームごとに一つしかポイントを追加しないけど、
ベクトルの配列をつなぐと配列の大きさの分だけポイントを追加する。
一番上にある0の定数ノードは、一つだけ発生させるか毎フレーム発生させるかの切り替えに使っていたけど、
実はコレの正体は他のエミッターにある「SelectRateType」パラメーターでした。
なので、コレが0の時は「Number of Particles Per Second」
なのでConvertRatePerSecondToNumPerFrameノードで秒毎からフレーム毎に変換した値に、1の時は
「Total Number of Particles」なのでスカラー型から整数型に変換した値が配列の大きさになるようになっている。
で、左端の100ってのが発生レート。
さらにノードを追加して、ヌルからパーティクルを発生させるようにした。

ヌルをICEツリーにドロップして「Get null」を追加、さらに「GetData」を追加してInNameポートに繋げる。
GetDataのプロパティを表示して「.kine.global」と入力。MatrixToSRTを追加してGetDataから繋げる。
BuildArrayFromConstantのValueポートに繋がっていた(0,0,0)の定数ノードを削除して、
MatrixToSRTのTranslationと繋ぎ替える。
こうするとヌルのグローバル座標がパーティクル発生位置に設定される。
さらにヌルの向きに沿ってパーティクルの発生方向を変えたいので、
RotateVectorを追加してパーティクルの発射方向をヌルの回転値で回転させる。
これでコーンエミッターが完成したけど、後々使いまわせるようにコンパウンド化しておく。

Executeノードをブランチ選択してコンパウンドを作成。
とりあえず「Get null」をコンパウンドの外に出す。
Get.kine.globalのInNameポートは外部公開ノードにしておく。


「Get null」をカット&ペーストでコンパウンドの外に出して、コンパウンドのInNameポートに繋げ直す。
さらに外部公開ポートを追加。

いくつかのポート名をリネームして、SelectRateTypeポートのプロパティからComboValuesを設定。
一応完成はしたけど、発射方向がY軸だけじゃなくXやZ方向と切り替えが出来るようにノードを追加。

RandomizeRotationByConeのConeAxisに繋がるところにノードを追加。
SelectCaseを追加してX、Y、Zを切り替えると基準方向が変わるようにした。
向きを逆に出来るようにNagativeパラメータ(Bool型)を追加。
コレがTrueの時には向きに-1を掛けて逆向きになるようにした。
これで完成といきたいところだけど、

なんかプリセットのコンパウンドってポートがグループ化されてるじゃん?
あと、こっそりコンパウンド名の設定と、Enableパラメータを追加した。

で、ポートのグループ化はXSI上では出来ないっぽいけど、 一旦エクスポートした後でファイルを直接書き換えることでグループ化させることが出来た。

↑のように「group」タグを挿入するとグループ化出来る。





