[Maya] Ground Impact System解説

ちょっと時間が空いてしまってアレですが、Ground Impact Systemの中身を軽く解説します。

Maya Fluid Ground Impact System WIP 01 from taikomatsu on Vimeo.


こちらは以前お伝えした通り、米岡さんがtpとFumeで作成されたものを、Mayaで真似て作ってみたものです。

TP ground impact system v001 from Kei Yoneoka on Vimeo.

米岡さんのものがテクスチャのカラーをベースにパーティクルの速度を決定しているのに対し、僕のは全てエクスプレッションで制御されています。
これに関しても以前の記事でお伝えした通り、Mayaだといちいち板を作成してあれこれ設定して、、というのが個人的に面倒に思えたから全てをエクスプレッションで行うことにしました。

というわけで早速解説に入ります。

使用しているオブジェクトは以下の通りです。
gis_objects

重要なものを簡単に説明をすると、

    • prt_bomb

爆弾パーティクルです。これがコリジョンオブジェクトに衝突した際にイベントが発生し、prt_expl_leaderがエミットされます。

    • prt_expl_leader

コリジョンイベントで発生するパーティクルです。このパーティクルはprt_expl_smokeEmitterのエミッタになっています。

    • prt_expl_smokeEmitter

Fluidのエミッタ用のパーティクルです。

    • fluid1

煙を作成するためのFluidコンテナです。

    • cll_plane

prt_bombのコリジョンオブジェクトです。

といった感じになります。

 
まずは簡単に流れを追って順に解説します。

 
まず、prt_bombがemt_bombからエミットされます。
prt_bombがコリジョンオブジェクト(このシーンではcll_plane)に衝突するとイベントが発生し、prt_expl_leaderがエミットされます。
prt_expl_leaderはポイントエミッタになっており、prt_expl_smokeEmitterをエミットします。
prt_expl_leaderprt_expl_smokeEmitterをエミットしたフレームで消えます。つまりlifespanは1フレ(1.0/FPS)に設定されています。
prt_expl_smokeEmitterをトゲトゲ形状にするために、いくつかのデータをprt_expl_leaderから引っ張ってこないといけないのですが、その際にparentIdを使用してデータを引っ張ってくるためにちょっとした細工をしてやる必要があります。これは後で詳しく解説します。
そしてエミットされたprt_expl_smokeEmitterは、エクスプレッションでもにゃもにゃすることでトゲトゲ形状になるように設定してやります。
これもあとで詳しく。
そしてそれを使ってfluidコンテナにdensityをエミットすることでトゲトゲ煙の完成です。

なんとなくの流れは掴んで頂けたでしょうか?
実際にデータを見て頂くと理解も深まると思うので、是非併せてどうぞ。

さて、ここからがキモ、prt_expl_leaderprt_expl_smokeEmitterのエクスプレッションの解説を行います。
まず最初はprt_expl_leader

global vector $pVelocity[];
global vector $pOrigin[];
seed(prt_expl_leaderShape.particleId);
int $id = prt_expl_leaderShape.particleId;
float $r = rand(0.3, 1.0);
vector $p = prt_expl_leaderShape.position;
vector $v = prt_expl_leaderShape.velocity;
vector $up = <<0, 1.0, 0>>;
vector $projv = unit(cross($up, unit(cross(unit($v), $up))));
vector $offp = $projv * $r * prt_expl_leaderShape.positionScatterRadius;
float $vy = ($v.y < 0) ? -$v.y : $v.y;
$v = <<$v.x*prt_expl_leaderShape.velocityMultX, $vy*prt_expl_leaderShape.velocityMultY, $v.z*prt_expl_leaderShape.velocityMultZ>>;
$v *= $r;
$p += $offp;
prt_expl_leaderShape.velocity = $v;
prt_expl_leaderShape.position = $p;
$pVelocity[$id] = $v;
$pOrigin[$id] = $p;

これはprt_expl_leaderのCreation Expressionです。
Runtimeはどちらも使用しません。

上から順に解説します。

global vector $pVelocity[];
global vector $pOrigin[];

これはグローバル変数の宣言で、$pVelocity, $pOrigin、ともにvector型の配列です。
パーティクルエクスプレッションでグローバル変数を使用するのはなかなか見慣れないかも知れません。
これはprt_expl_smokeEmitter内で、親のvelocityとpositionを取得するために必要になります。

というのもMayaではパーティクルからパーティクルを発生させた場合、親、つまり自分を発生源となったパーティクルの情報がid以外取得できないのです。positionもvelocityもダメです。少なくとも僕の知る限りでは。
なので一旦グローバル変数に値を格納し、後でidを指定することで値を取得出来るようにしたいわけです。
実際の代入は最後に行なっているのですが、パーティクルエクスプレッション内でグローバル変数を使用する際には宣言が必要なので、このエクスプレッションではグローバル変数を使用していることを明示的にするために、冒頭で宣言しています。

seed(prt_expl_leaderShape.particleId);

自分のidを指定してseedを行い、乱数ストリームを初期化しています。
これを行うとrandの値が安定するので、計算をかける毎に結果が異なる、と言ったことが起こりません。

int $id = prt_expl_leaderShape.particleId;
float $r = rand(0.3, 1.0);
vector $p = prt_expl_leaderShape.position;
vector $v = prt_expl_leaderShape.velocity;
vector $up = <<0, 1.0, 0>>;

各種変数の初期化を行なっています。
$idはパーティクルID、$pはパーティクルのポジション、$vはvelocity、$upはアップベクトルを手動で設定してあります。
$rはこの後で使用する乱数です。どう使うかはこの後でやります。
$id, $p, $vに関しては、prt_expl_leaderShape.particleIdなどと記述することで直接値の読み出しが出来るわけなのですが、コードの中にこんな長いものがいちいち埋めこまれてしまうと非常に読みづらくて敵わないので、頻出する値は一旦名前の短い変数に格納する、ということを個人的によくやります。可読性の向上のためということですね。

vector $projv = unit(cross($up, unit(cross(unit($v), $up))));
vector $offp = $projv * $r * prt_expl_leaderShape.positionScatterRadius;
float $vy = ($v.y < 0) ? -$v.y : $v.y;
$v = <<$v.x*prt_expl_leaderShape.velocityMultX, $vy*prt_expl_leaderShape.velocityMultY, $v.z*prt_expl_leaderShape.velocityMultZ>>;
$v *= $r;
$p += $offp;

ここが一番ややこしいので一気に行きます。

このパートではパーティクルの発生点を衝突平面上にオフセットをしています。

通常パーティクルをイベントで発生させると、コリジョンが起こったまさにそのポイントが発生点になります。
そうするとどこから発生したかが明確すぎたり、発生点付近に必要以上にポイントが固まったりしてしまいます。
完全な点から発生するよりも、多少範囲を持って発生した方が良い結果につながるのではと思い、こういう仕組みを組み込んでみました。

$projvは衝突平面に対して投影されたベクトルを取得するための処理です。
もうunit()cross()だってえらいことになってますね。。

図解するとこうです。

cross_explanation_01

$upはアップベクターのことで、先程手動で設定したものです。
$vはvelocityです。
それらのcross、つまり外積を求めることで、その2つのベクトルに直交するベクトルが取得できます。
言い方を変えると、その2つのベクトルからなる平面の法線が取得できます。
それを使ってさらに別のベクトルを求めると、平面上に投影された$vが取得できます。

最初のcross()の際、$vunit()でnormalizeしています。
もし元々のvectorの大きさを残したまま処理が行いたいのであればunit()は使用しないほうがいいのですが、まぁ今回は別にどっちでもよかったのでなんとなく気分で入れただけだったような気がします(ええぇぇえぇ
この場合はあんまり深い意味はないです。

また、もう少し複雑なシーンまでを想定して書いてみたのですが、今回みたいに衝突面がY=0の平面であれば$v.yを0にするだけでOKだったりもします。あと$upは平面の法線という意味で$Nにした方がわかりやすかったかも知れませんね。。

・・・。

それはそうと次です。

$offpでは上で求められた$projv(平面上に投影された$v)を使用して、ポイントをオフセットするためのベクトルを作成しています。
これを$pに足すことでポイントのオフセットを行います。
positionScatterRadiusというのはコントロール用に作成したカスタムアトリビュートで、オフセットの半径を設定します。
先ほど作った$rもここで使用されています。

その次の$vyの箇所は若干見慣れない書式になっていると思いますが、これは三項演算子と言うものです。
個人的にはすごく好きで頻繁に使用するのですが、人によっては毛嫌いする人もいるようです。
これは簡単なif文のようなもので、if文で書き直すと以下のようになります。

if ($v.y < 0) {
$vy = -$v.y;
} else {
$vy = $v.y;
}

僕はコンパクトにまとまるので好きなのですが、これは好みに応じてif文などと使い分けてもらえればOKだと思います。

ガンガン行きます。
次は$vの要素にそれぞれ別のコントロール用カスタムアトリビュートが掛けられています。
単純に速度をXYZ要素ごとにスケーリングしているだけなのですが、これはつまりトゲトゲ形状のコントロールを行うためのものです。
ここである程度の分布を決めてからトゲトゲを作るので、大きな形状はここの値でいじる必要があります。
サンプルのシーンだと1, 2, 1となっており、多少縦方向に伸ばそうとしていることがわかります。

次に$v$rを掛けることで、offsetの小さいものほど速度が遅くなるようになります。
ホントは中心ほど大きくなるんじゃねえの?とも思うんですが、この時の僕はそう思ったようです(ぇえええ

最後に$p$offpを足して、パーティクルポジションのオフセットを行います。
サンプルシーンではpositionScatterRadiusの値が15になっており、そこそこ広い範囲にオフセットさせられているようです。
これはシーンのスケールによるので、一概に大きな値と言えるわけではありませんが。

$pVelocity[$id] = $v;
$pOrigin[$id] = $p;

最後に更新した$v, $pを最初に作ったグローバル変数の中に突っ込んで、このパーティクルのエクスプレッションは終了です。
この際$idで値を代入してやるのがミソです。

先ほど、これらのグローバル変数に格納した値は後にprt_expl_smokeEmitterで使用すると述べました。
その際取得できる親のパラメータはidだけ。なのでidを頼りに値を引き出さないといけません。
その為にここで予めidを使用して値を格納しておくわけです。

間違った場所にデータを格納するとおかしなことになってしまうので注意が必要です。
まぁそれでも何かしら動くんじゃないかとは思いますが、意図しない動きになるとその後の修正がしんどいので、意図して動きを作るというのが重要です。

 
さぁここまででもだいぶ長いですが、まだまだ行きます。
次はprt_expl_smokeEmitterです。

こちらもCreation Expressionのみです。

global vector $pVelocity[];
global vector $pOrigin[];

seed(prt_expl_smokeEmitterShape.particleId);
int $pid = prt_expl_smokeEmitterShape.parentId;
vector $pv = $pVelocity[$pid];
vector $po = $pOrigin[$pid];
float $r = prt_expl_smokeEmitterShape.scatterRadius * pow(rand(1.0), prt_expl_smokeEmitterShape.radiusRandomExp);
float $spd = mag($pv);
float $mv = prt_expl_smokeEmitterShape.multVelocity;
float $exp = prt_expl_smokeEmitterShape.initialVelocityExp;
float $pi = 3.14159265;

vector $p = sphrand(1.0);
$p = <<$p.x, 0, $p.z>>;

vector $worldup = <<0, 1.0, 0>>;
vector $v = $pv;
vector $nv = unit($v);
vector $rotAxis = unit(cross($worldup, $nv));
float $angle = dot($nv, $worldup)*0.5*$pi;
$p = rot($p, $rotAxis, $angle);
vector $newp = $p * $r + $po;
prt_expl_smokeEmitterShape.position = $newp;

float $dist = 1.0 - clamp(0, 1, mag($p));
vector $newv = <<0, pow($dist, $exp), 0>>;
$newv = rot($newv, $rotAxis, $angle);
prt_expl_smokeEmitterShape.velocity = $newv * $spd * $mv;

prt_expl_smokeEmitterShape.lifespanPP = prt_expl_smokeEmitterShape.lifespan*rand(0.04);

prt_expl_smokeEmitterShape.rgbPP = <<1., 1., 1.>>;

このエクスプレッションでは、prt_expl_leaderから適当にエミットされたパーティクルを良い感じに配置、設定しなおしています。
具体的には、親のprt_expl_leaderが飛んだ方向にトゲトゲの形状が伸びるようにする、中心ほど強いvelocityを持つ(これでトゲの形状を津kリます)、という感じでしょうか。
実際の処理はもっと細かくあれこれやっています。

こちらも上から順に行きます。
seed()までは先程のと同じような処理なので割愛します。

int $pid = prt_expl_smokeEmitterShape.parentId;
vector $pv = $pVelocity[$pid];
vector $po = $pOrigin[$pid];

ここが先ほど述べた、idを元に親の情報を取得するための部分です。
簡単ですよねw

parentIdは自分を発生させた親パーティクルのidを取得するためのPPAttrです。
自分で作成する必要がありますが、Particleタブにプリセットとして登録されているので選んでOKを押すだけです。

そしてそのidを使って、グローバル変数の配列にアクセスし、データを取得します。
こんだけです。

簡単ではあるんですが、グローバル変数を使う必要があるのが個人的には非常に気に食わないので、どなたか別のいい方法ご存知であればご教示頂きたいですm(__)m

では次。

float $r = prt_expl_smokeEmitterShape.scatterRadius * pow(rand(1.0), prt_expl_smokeEmitterShape.radiusRandomExp);
float $spd = mag($pv);
float $mv = prt_expl_smokeEmitterShape.multVelocity;
float $exp = prt_expl_smokeEmitterShape.initialVelocityExp;

各種変数を作成しています。
$rはトゲトゲの半径を決定するための変数です。scatterRadius, radiusRandomExpはカスタムアトリビュートになります。
scatterRadiusでトゲトゲの円錐形の半径を決定します。
radiusRandomExpはどこにパーティクルが集中するかを決めるためのパラメータです。
たとえば1とした場合、円の中に一様にパーティクルがばら撒かれます。2, 3など、1より大きい場合、大きければ大きいほど中心に多くのパーティクルが配置されます。逆に0.5など1より小さい場合は円の外側に多く配置されます。
pow()を使ってradiusRandomExpの値で累乗することでこれを実現しています。

$spd$pvの大きさを取得しています。
mag()はmagnitudeの略で、vectorの大きさを取得できます。

$mv, $expは例によってカスタムアトリビュートを代入しています。

vector $p = sphrand(1.0);
$p = <<$p.x, 0, $p.z>>;

$pはパーティクルの位置を決めるための変数です。
ですがここで最終的な位置を決めているわけではありません。
ここではsphrand()を使って単位球の中の1点を求めた後、Yの要素を0にすることで単位円の中の1点を求めています。
この場合球を潰して円にするイメージなので、デフォルトで中心に点が集まりがちになるのですが、まぁこまけぇこたぁいいんだよ!ということでとりあえずOKとしています。
問題が起こるまではノリであれこれやっちゃっていいかなーというのが個人的なスタンスです。

vector $worldup = <<0, 1.0, 0>>;
vector $v = $pv;
vector $nv = unit($v);
vector $rotAxis = cross($worldup, $nv);
float $angle = angle($worldup, $nv);
$p = rot($p, $rotAxis, $angle);
vector $newp = $p * $r + $po;
prt_expl_smokeEmitterShape.position = $newp;

$worldupは例によって手動で設定したup vectorです。
なんでさっきと名前が違うかはわかりません。ノリです。
ホントはあまり望ましいことではないのですが、まぁ小さなエクスプレッションなので良しとしました。

$vには$pvを代入し、その後$nvでそれをnormalizeしています。
$vはこの後どこでも使われてないのでそのまま$nv = unit($pv)とすればよかったのですが、試行錯誤の残り香を感じてください(ぉ

余談ですが、変数の名前などはある程度自分ルール決めてしまうと毎度名前に困らなくて良いので便利です。
ある程度その中身が想像できるものが良いとは思います。
僕は$p, $v, $nv, $mv…などを良く使っています。
p, vはそのままで、$nvはnormalized velocity、$mvはvelocityのmagnitude、といった具合です。

$rotAxisでまたcrossが出てきました。
$worldup$nvの直行ベクトルを求め、後にparticleの位置を決める為の回転軸として使用します。

$angleは、パーティクルを移動させる際に使用するrot()で必要な角度情報を求めています。
angle()は2つのベクトルのなす角をラジアンで返してくれます。便利です。
このすぐ使うrot()では、回転角をラジアンで要求するため、このまま値が使用出来ます。

rotは、第一引数に与えたベクトルを第二引数の回転軸($rotAxis)に対して第三引数分だけ回転させたベクトルを返す関数です。
この場合、$p$rotAxisに対して$angle分回転させています。

図解するとこんな感じです。

rot_explanation

絵が下手なので逆に分かりづらくなったらすみません、、
rotAxisに沿ってangle分だけ回したってのが伝わればOKです。

これによって、一旦仮にXZ平面上にばらまいたポイントを、v方向に向けることが出来ます。
Y-upの平面をv方向に向けている感じです。

そしてそこで得た値に$rをかけて大きさを調整し、$poを足して本来の発生点、つまり親パーティクルの発生点付近にオフセットします。
これをpositionに設定することで、パーティクルの位置の調整は完了です。

float $dist = 1.0 - clamp(0, 1, mag($p));
vector $newv = <<0, pow($dist, $exp), 0>>;
$newv = rot($newv, $rotAxis, $angle);
prt_expl_smokeEmitterShape.velocity = $newv * $spd * $mv;

$distに関しての計算も、これもまた良くわからない感じですが、$pの大きさを求め、それを0-1にクランプし、その値を反転させています。反転という言い方が数学的に正しいかちょっとわかりませんが・・・。
これは$pが半径1の円上のランダムな点であるという性質から、mag()を取ると最大値が1.0になるという性質を利用したものです。
一応エラー対応のためにclamp()を使って0-1にクランプをしています。
その値を1から引くことで反転させています。
これによって円の外側にあるものほど値が小さく、中心に近いものほど値が大きくなります。
この際、値が0-1に収まっていることで、この後の調整がしやすくなるというメリットがあります。

rot()の後の$pを使用することで若干ややこしい感じはしますが、ここで必要な性質、つまり大きさに関してはrot()の後でも変わりませんし、ある程度まとめて書いたほうが見通しも良くなると思ってこのような記述にした記憶があります。mag($p)を$pを求めたすぐ後に求めて別変数に格納しておくほうが美しいのではという気もしますが、とりあえず他と同様にそのまま掲載しました。

$newvでは上向きのvectorを作成しています。
pow($dist, $exp)とすることで、トゲの最終的な形状をコントロールすることができます。
上でも述べた通り、powは累乗を計算する関数で、例えばここで$expが2.0だったとすると、中心から遠くなるほど移動量が少なくなり、結果中心部に近いところだけが鋭く尖るような形になります。1の場合はリニアで減衰するので、円錐の様な形になります。
これを3, 4,,と増やしていくと更に顕著に中心だけが残った形になり、逆に1より小さくしていくと中心部から離れても移動量の減衰が小さくなり、トゲというかむしろ放物線の様な形状になります。

これもまた同様にrot()で目的の向きに向かせます。
第一引数以外は先ほどと同じ値を使用しています。

そしてまた先ほどと同様に、$newvの大きさを調整します。
$mvを掛けることで親の速度を継承し、$spdではカスタムアトリビュートにより細かな調整を行います。

prt_expl_smokeEmitterShape.lifespanPP = prt_expl_smokeEmitterShape.lifespan*rand(0.04);

最後にlifespanの設定をします。
0.04というのは1.0/24.0を近似した値で、24FPS環境での1フレ辺りの秒数を表しています。
24FPSでは1フレ約0.04秒ということです。
こうすることで、lifespanに設定した値を秒ではなくフレームとして扱うことができます。

例えばlifespanを10に設定した場合、0-0.4までのランダムな値が設定され、最大でも10Fで消えます。
prt_expl_smokeEmitterは消滅するまでの時間をフレームで設定したほうが分かりやすそうだなーと思い、このような記述にしてあります。

さーー以上でエクスプレッションの解説は終了です。
大変大変お疲れ様でした。

一見複雑風ですが、一度データを確認して頂けると実際そこまででもない事が分かるかと思います。
こちらの記事はその際の参考に使用して頂ければ幸いです。

何かあればメールなりコメントなりでご質問ください。
時間を見つけて出来る限りご回答させて頂きたいと思っています。

よろしくどうぞ(・・)ノシ

「[Maya] Ground Impact System解説」への9件のフィードバック

  1. え、エフェクトってこんなに難しいんすか、、、?
    俺には無理です!
    餅は餅屋でエフェクト人に任せますーw

  2. >succhin。さん
    難しい、、ですかね、、
    まぁ確かにこの辺の関数とかの扱いになれてないとそういう感じかもしれませんが、この程度であれば多分慣れ次第かも、とも思います。
    僕もこれ以上難しいことは出来ませんし・・・w

    餅屋として仕事を任せてもらえるように引き続き頑張りたいと思います!w

  3. 死ぬほど勉強なります!
    最近内積・外積・ベクトルの基礎等勉強してる中、
    めちゃめちゃ為になりました。
    ホントtaiさんいなかったらもっと時間かかって理解してたと思いますw

    特にそれぞれのExpressionの解説はマジ助かりました。
    人のシーン見てても、何がノリで作ってるコードなのか解析するのに凄く
    時間かかるので特にありがたいところかと思っております。

    余談ですが、絵に関してはrotとかは2013のヘルプからそのままパクっても良かったんじゃないですかね?僕はわかりやすいと思いましたが!

  4. >gameeffectさん
    おっ!喜んでいただけて何よりです!
    内積は僕も割と早い段階ですんなり理解できて頻繁に使ってたんですが、外積は何が何やら全く分かってなくて、比較的最近使うようになりましたw

    なんだかんだMayaにはExpressionがあるので、個々のパーティクルの動きの制御は未だにあまり困らないんですよね。最近のノードベースのソフトに比べると多少面倒なところもありますが、コードを書くことによるメリットもないわけではないですし。あと知識自体はソフトを移っても有効ですし、勉強して損はないと思っています:)

    絵!!ヘルプにあったんですね・・・全く気づいてませんでした!w
    うわー、いらんところに地味に時間かけてしもた・・・ww
    ご指摘ありがとうございます!

  5. まだ途中なのですが、解析させて頂いて幾つか疑問点がありますので、
    こちらに記載させて頂きます。時間あるときにでも教えていただけると助かります。
    自分の理解は最後にコードにコメントのせさせてもらったので、ご参照頂ければと思います。その上で以下2点について質問です。

    ・$vに$rを掛けて何故オフセットの小さいほうが遅くなっていくのか?
     ⇒Creationに書かれているエクスプレッションなので、$projv出すときには影響してないのかなと思っていますが、するんでしょうか?

    ・$projv出す時にunit入れなくていいって話ですが、一番外側のやつだけは必要だと思うんですが・・
     ⇒これ抜くと大きく挙動が変わりましたので。。でもこれは代わりに下記の記述を
     vector $offp = $projv * $r * prt_expl_leaderShape.positionScatterRadius;
    抜いてやれば問題なかったりしますでしょうか?印象としてはスカラー値持ってるのに、更に値かけるからとんでもないことになるのかなと思ったりしてます。
     
    以下コード(ちょっと整理しやすいように記述が前後してますが、問題あるようでしたら底も突っ込んで頂ければ幸いです。)

    ***定義領域***
    //グローバル変数宣言
    global vector $pVelocity[];
    global vector $pOrigin[];

    //ランダム値固定
    seed(prt_expl_leaderShape.particleId);

    //ParticleIDを変数化
    int $id = prt_expl_leaderShape.particleId;

    //ランダム値を変数化
    float $r = rand(0.3, 1.0);

    //positionとVelocityを変数化
    vector $p = prt_expl_leaderShape.position;
    vector $v = prt_expl_leaderShape.velocity;

    //UPベクターを定義
    vector $up = <>;
    ***終了***

    ***Positionオフセット値導出***
    //パーティクルのVelocityとYに直行するベクトルを導出。
    //上記で求めたベクトルとYに直行するベクトルを導出。
    //このベクトルを正規化して求めたベクトルの方向のみを代入。
    vector $projv = unit(cross($up, cross($v, $up)));

    //オフセット用のベクトルを作成。
    //上記で求めたベクトルの方向にランダム値を乗算、更にカスタムアトリビュートの値を乗算し、ベクトルのスカラー値を設定。
    //この値をオフセット用ベクトルとして変数に代入。
    vector $offp = $projv * $r * prt_expl_leaderShape.positionScatterRadius;

    //positionにオフセットベクトルを足した値を代入。
    $p += $offp;
    ***終了***

    ***Velocityの値調整***
    //VelocityのY方向の値が0未満である場合、左記の値に-1を掛けた値を変数に代入。
    //上記以外の場合はVelocityのY方向の値をそのまま代入。
    float $vy = ($v.y < 0) ? -$v.y : $v.y;

    //各軸に対してカスタムアトリビュートの値を乗算し、velocityに代入。
    $v = <>;

    //velocityにランダム値を掛けた値を代入。
    $v *= $r;
    ***終了***

    ***導出した各データを代入***
    //調整したvelocityの値とオフセット値を与えたpositionの値をそれぞれ戻す。
    prt_expl_leaderShape.velocity = $v;
    prt_expl_leaderShape.position = $p;
    //グローバル変数にIDを引数にvelocityとpositionを格納
    $pVelocity[$id] = $v;
    $pOrigin[$id] = $p;
    ***終了****

    長々とスイマセンが、良かったらよろしくお願い致します。

  6. >gameeffectさん
    おおっ!本格的なご質問ありがとうございます。
    参考にして頂いて嬉しいです:)

    >・$vに$rを掛けて何故オフセットの小さいほうが遅くなっていくのか?
    こちらは解説にもちょろっと書いているのですが、多分これは特に意味がない記述だと思われます。その当時の僕はそう思ったようですwwもしかしたら無い方が結果は良いかも知れませんねー。

    >・$projv出す時にunit入れなくていいって話ですが、一番外側のやつだけは必要だと思うんですが・・
    これはすみません、書き方悪かったです
    > vector $projv = unit(cross($up, unit(cross(unit($v), $up))));
    元々のやつだとunitが2個発見できると思うのですが、それの最初に計算される方のがいらないということです。
    unit(cross(unit($v), $up)) を cross($v, $up) としてやっても問題ありませんということです。
    この場合単位ベクトルが欲しかったのですが、必要以上にunit()しちゃってたという感じです:p

    コメントもこんな感じで合ってると思います。
    途中<と>に挟まれちゃった部分がHTMLのタグとみなされたか何かで消えちゃってますが、コード自体への変更はなさそうですしコメントに関しては問題ないかと!
    <は&lt;、>は&gt;と書くと問題なく記述できるようです。面倒ではありますが・・・w

  7. 長文コメントすんません^^;
    回答有難う御座いました!
    参考なります!引き続き学ばせてもらいますー

    後、消えてしまってるところ見落としてました・・
    こちらについてもありがとうございました!

  8. を作っていただけたら買っちゃいそうです。

    Mayaはちょっとでも先に進もうとするといきなり敷居が跳ね上がります。。

  9. コメントありがとうございます。
    トゲトゲパーティクル生成ツール、ですか。
    これのセットアップを簡単に行うツールぐらいは書けると思いますが、まぁその程度のものは売り物ってほどでもないから違いますかね、さすがにw

    Mayaは書かないと先に行けないということが結構多いので、プログラミング力の向上だと思って積極的に取り組むしかないと割り切ってます!w

コメントを残す

メールアドレスが公開されることはありません。