ON-BLOG

CGのこと、あれこれ書いてます。

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;
		}
	
}

f:id:tommy_on:20130625233420p:plain

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;
		}
}

画像みたいに衝突した所でパーティクルが発生しますね。
f:id:tommy_on:20130625233511p:plain
あとこれ誤字で止まる事がありすぎて泣きそうになりました。。。。
では説明↓

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自体の説明は終わりっぽい。
次からは細かい部分と基本に変える感じになると思います。

では…