XSIユーザーから観たMELスクリプトについて 其の二十
次にパーティクルのゴール
パーティクルによくあるやつです。
ではコード↓
global proc makeString1() { string $text[] = `textCurves -f "Times-Roman" -t "Maya"`; string $chars[] = `listRelatives $text[0]`; string $psurf[]; int $i = 0; for($curv in $chars) { string $pln[] = `planarSrf -polygon 1 $curv`; $psurf[$i] = $pln[0]; setAttr ($psurf[$i] + ".v") 0; $i++; } for($ps in $psurf) { string $ename[] = `emitter -pos 1.5 10.0 1.5 -type "direction" -dx 0.0 -dy -1.0 -dz 030 -spread 0.2`; string $pname[] = `particle`; setAttr ($pname[0] + ".particleRenderType") 4; string $shp[] = `listRelatives -s $pname`; addAttr -ln "radius" -at "float" $shp; setAttr ($shp[0] + ".radius") 0.05; connectDynamic -emitters $ename[0] $pname[0]; goal -goal $ps -weight 0.2 $pname[0]; setAttr ($pname[0] + ".conserve") 0.9; } }
string $text[] = `textCurves -f "Times-Roman" -t "Maya"`;
文字オブジェクト作成。
string $chars[] = `listRelatives $text[0]`;
テキストのノード名前を代入。
for($curv in $chars)
「M」「a」「y」「a」分回される。
string $pln[] = `planarSrf -polygon 1 $curv`;
プランナーサーフェースを実行して文字のポリゴンとして作成し、代入。
この-polygon 1は以下の通りでタイプを決めれる。
0.Nurbsサーフェース 1.ポリゴン 2.サブディビジョンサーフェース 3.ベジェ 4.サブディビジョンサーフェースソリッド
あと、このプランナーサーフェースはSIでいう、「Nurbsからメッシュ」的な感じ。
$psurf[$i] = $pln[0];
プランナーサーフェースを代入。
setAttr ($psurf[$i] + ".v") 0;
visibilityをOFFに設定。.vはvisibilityの略。
$i++;
変数iに1加算する。これで$psurfに順番ずつ格納される。
for($ps in $psurf)
上で加算された値分回す。
string $ename[] = `emitter -pos 1.5 10.0 1.5 -type "direction" -dx 0.0 -dy -1.0 -dz 030 -spread 0.2`;
エミッターを作成し、タイプをディレクションに設定。
setAttr ($pname[0] + ".particleRenderType") 4;
タイプ4は球体。
string $shp[] = `listRelatives -s $pname`;
$pname=パーティクルに代入されているシェイプノード名を代入。
何回か出てるが、listRelatives -s 自体の説明。
オブジェクトの、親子階層に関する情報取得するコマンドで、
- c(children)
- ad(allDescendents)
- s(shapes)
- p(parent)
- ap(allParents)
- pa(path)
- f(fullPath)
- ni(noIntermediate)
- typ(type)
こんなけあります。
アンダーバー1文字とかすげぇわかりづらいわ。
ちゃんと書いてほしいっす。
addAttr -ln "radius" -at "float" $shp;
上で追加したシェイプノードにfloat型のアトリビュートを追加(radiusは半径を表す)
setAttr ($shp[0] + ".radius") 0.05;
シェイプの半径に0.05を代入。
connectDynamic -emitters $ename[0] $pname[0];
エミッターへリンク
goal -goal $ps -weight 0.2 $pname[0];
パーティクルゴールをプランナーサーフェースに設定。影響力を0.2に設定
setAttr ($pname[0] + ".conserve") 0.9;
定着率を決定0.9なので、あんまり定着しない。
これは中々ややこしいですね。
噛み砕いていくと大した事ないんですが。。
ではその応用編
パーティクルの数と放出期間のアニメーションの設定。
global proc makeString2() { string $text[] = `textCurves -f "Times-Roman" -t "Maya"`; string $chars[] = `listRelatives $text[0]`; string $psurf[]; int $i = 0; for($curv in $chars) { string $pln[] = `planarSrf -tol 0.01 -polygon 1 $curv`; $psurf[$i] = $pln[0]; setAttr ($psurf[$i] + ".v") 0; $i++; } for($ps in $psurf) { string $ename[] = `emitter -pos 1.5 10.0 1.5 -type "direction" -dx 0.0 -dy -1.0 -dz 030 -spread 0.2`; currentTime 0; setAttr ($ename[0] + ".rate") 300; setKeyframe ($ename[0] + ".rate"); currentTime 30; setAttr ($ename[0] + ".rate") 0; setKeyframe ($ename[0] + ".rate"); keyTangent -outTangentType "step" -attribute "rate" $ename[0]; string $pname[] = `particle`; setAttr ($pname[0] + ".particleRenderType") 4; string $shp[] = `listRelatives -s $pname`; addAttr -ln "radius" -at "float" $shp; setAttr ($shp[0] + ".radius") 0.05; connectDynamic -emitters $ename[0] $pname[0]; goal -goal $ps -weight 0.2 $pname[0]; setAttr ($pname[0] + ".conserve") 0.9; } }
重要なのはここです。
currentTime 0; setAttr ($ename[0] + ".rate") 300; setKeyframe ($ename[0] + ".rate");
カレントを0にして、レート300にしてレートにキーフレーム
30F側も同じくキーイングしてアニメーションさせてます。
いや~楽しいっすよ。これw
この感じで次は衝突があった時にパーティクルを発生させるというものを作ります。
まずはこのコードから
global proc makeSpark1() { string $gra[] = `gravity -magnitude 9.8`; polySphere; move 1 10 1; rigidBody -active; connectDynamic -fields $gra[0]; polyPlane; scale 20 1 20; rotate 0 0 -45; string $rb = `rigidBody -passive`; expression -object $rb -string ("makeEmitter1(\"" + $rb + "\", contactCount)"); setAttr rigidSolver.contactData 1; } global proc makeEmitter1(string $rigidbody, int $contval) { if($contval > 0) { string $pp[] = `rigidBody -q -contactPosition $rigidbody`; string $pos[]; tokenize $pp[0] $pos; string $emi[] = `emitter -pos $pos[0] $pos[1] $pos[2]`; string $pname[] = `particle`; connectDynamic -em $emi[0]; setAttr ($pname[1] + ".particleRenderType") 6; setAttr ($pname[1] + ".lifespanMode") 2; setAttr ($pname[1] + ".lifespanRandom") 0.5; setAttr ($pname[1] + ".lifespan") 5; } }
画像みたいに衝突した所でパーティクルが発生しますね。
あとこれ誤字で止まる事がありすぎて泣きそうになりました。。。。
では説明↓
string $gra[] = `gravity -magnitude 9.8`;↓ connectDynamic -fields $gra[0];↑
重力とリジッドボディの設定ですね。いつもどおりです。
polyPlane; string $rb = `rigidBody -passive`;
パッシブ側の設定。
expression -object $rb -string ("makeEmitter1(\"" + $rb + "\", contactCount)");
パッシブボディにエクスプレッションを仕込みます。
中身はファンクションに飛ぶ式です。-string ("makeEmitter1(\"" + $rb + "\", contactCount)")
で「"makeEmitter1(rigidBody\, contactCount)")」となり関数の引数が設定されてます。
contactCountは接触アトリビュートです。「現在のフレームのコンタクトの数」となります。
要は衝突できる数ですかね?
setAttr rigidSolver.contactData 1;
衝突したかのフラグ用?
global proc makeEmitter1(string $rigidbody, int $contval)
ここで上で定義した引数を使って関数の定義をしていきます。
if($contval > 0)
衝突した点が0以上なら実行。
string $pp[] = `rigidBody -q -contactPosition $rigidbody`;
衝突した点の座標を配列に代入。
tokenize $pp[0] $pos;
文字列pp(座標)を分解して配列$posに代入。
このtokenizeはJsのsplitと同じっぽい。
なので、pp[0]がpp[1 2 3]だった場合。
pos[0] = 1 pos[1] = 2 pos[2] = 3 となる。
string $emi[] = `emitter -pos $pos[0] $pos[1] $pos[2]`;
エミッターを上で定義した場所に作成し、代入
string $pname[] = `particle`;
パーティクルを作成して代入
connectDynamic -em $emi[0];
エミッターにパーティクルをリンク
setAttr ($pname[1] + ".particleRenderType") 6; setAttr ($pname[1] + ".lifespanMode") 2; setAttr ($pname[1] + ".lifespanRandom") 0.5; setAttr ($pname[1] + ".lifespan") 5;
ここはパーティクルの設定。
上から
「タイプを球体に」
「ライフの範囲を2に」
「ライフの終了地点に0.5の分布を作成」
「ライフの設定」
なんでパーティクルは球体で寿命は5
個々のパーティクルには5から前後2の範囲で分布され、
さらに終了地点が5の場合ランダム0.5前後に終了地点が移動する。
という感じ。
あとはこれの応用編
アクティブパッシブを選択で、且つパーティクルの各所設定版
またパーティクルの衝突からの寿命も指定。
global proc makeSpark2() { string $oSel[] = `ls -sl`; string $gra[] = `gravity -magnitude 9.8`; select $oSel[0]; rigidBody -active; connectDynamic -fields $gra[0]; select $oSel[1]; string $rb = `rigidBody -passive`; expression -object $rb -string ("makeEmitter2(\"" + $rb + "\", contactCount)"); setAttr rigidSolver.contactData 1; } global proc makeEmitter2(string $rigidbody, int $contval) { if($contval > 0) { string $pp[] = `rigidBody -q -contactPosition $rigidbody`; string $pos[]; tokenize $pp[0] $pos; string $emi[] = `emitter -pos $pos[0] $pos[1] $pos[2] `; string $pname[] = `particle`; connectDynamic -em $emi[0]; int $fr = `currentTime -q` + 10; expression -o $emi[0] -s ("if(frame > " + $fr + "){rate = 0;}"); setAttr ($emi[0] + ".speed") 5.0; setAttr ($pname[1] + ".particleRenderType") 6; setAttr ($pname[1] + ".maxCount") 50; setAttr ($pname[1] + ".lifespanMode") 2; setAttr ($pname[1] + ".lifespanRandom") 0.5; setAttr ($pname[1] + ".lifespan") 1; addAttr -ln "lineWidth" -at "long" $pname[1]; addAttr -ln "tailFade" -at "float" $pname[1]; addAttr -ln "tailSize" -at "float" $pname[1]; setAttr ($pname[1] + ".lineWidth") 3; setAttr ($pname[1] + ".tailFade") 0.1; setAttr ($pname[1] + ".tailSize") 20.0; } }
string $oSel[] = `ls -sl`;
ここで選択物を全て取得。
select $oSel[0];
1つ目に選んだオブジェクトがアクティブになるように取得。2番目はパッシブ。
int $fr = `currentTime -q` + 10;
変数frに衝突時のカレントタイムから10F先を代入
expression -o $emi[0] -s ("if(frame > " + $fr + "){rate = 0;}");
エミッターにエクスプレッションを仕込み。
訳すと※カレントフレーム50Fで衝突したFが45Fの場合
エミッターに文字列ので式を代入
(int $fr = 45 + 10= 55 )
if(50 > 55){rate = 0;}
となる式になる。今は(false)なのでレートは変わらない。
これがカレントフレーム55Fになったら、
if(55 > 55){rate = 0;}
が成立して、レートが消えパーティクルも消えます。
要は衝突から10F先で止めたければこのように設定する。
addAttr -ln "lineWidth" -at "long" $pname[1]; setAttr ($pname[1] + ".lineWidth") 3;
パーティクルの設定に使用する為、アトリビュートを追加し設定している。
とここでMEL自体の説明は終わりっぽい。
次からは細かい部分と基本に変える感じになると思います。
では…