[maya] 超今更ですがパーティクルの基礎的な部分のリサーチ

Mayaのパーティクルのアトリビュートに関して、よく使う割にはなんだかんだ良く分かってないのであれこれテストしてみることにしました。
超地味な調査です。Maya Particle ギーク(つまり自分)向けです。

その1、ageに関して。

prt_01_age

これはDirectional Emitterから+Y方向にSpeed 1で10個のパーティクルを1Fでエミットした結果です。表示はNumericにしてageを表示しています。
フレームレートは30に設定してあります。
ばらばらですね。
Mayaでは1Fの中でも同じタイミングで全てがエミットされているわけではなく、1Fの間、この場合1.0/fps(30)=0.0333..秒のうちのどこかのタイミングでエミットされているということが分かります。
fpsが24なら1.0/24=0.04166..秒のうちのどこかのタイミングでエミットされるということになります。
つまり同じフレームで生まれたパーティクルでも、全く同じタイミングで発生しているわけではないということです。

ということは以下の様なExpressionは危険そうです。

if (age == 1.0)
  lifespanPP = 0;

ageが1になったら削除したい、という気持ちが空回りします。
実際に1秒後に1.0になるというわけではないなので、こういう場合には==での比較ではなく、>や>=などを使用すると漏れがないんじゃないかと思われます。

ちなみにこれは発生のタイミングが微妙にズレているだけで、velocityなどは同じなので要注意です。

prt_02_v

と、これをやった後で、Speedを0にしてExpressionでvelocityを与えたらどうなるんだろう?と思ったのでそれもやってみました。
今回はCreation Expressionで<<0, 1.0, 0>>と設定しています。

prt_05_v_age

全く同じ場所に来ました。
velocityは全く同じですが、右側のageの値の表示がごちゃごちゃしているのを見てもらうと分かる通り、それぞれ値は異なっているようです。

velocityは同じ、ageが違うという状況だけ見ると先ほどと同じですが、なぜこんな結果になってしまったかというと、おそらく評価のタイミングだろうと考えられます。
Emitterで値を設定した場合と、Expressionで値を設定した場合で、同じ意味を持たせたつもりでも違った結果が返って来ることがあるので要注意です。

その2、accelerationに関して。
accelerationは加速を司るアトリビュートで、fieldの結果などは基本的にこの値に反映され、それによりパーティクルが動かされます。
ただし、想像しづらいパラメータであることもあり、あまり活用されていない感じもある(あくまで自分の中での話です)ので、一旦ここも突っ込んでみてみます。

まずは分かりやすく、Creation Expressionでaccerelation = <<0, 1.0, 0>>と設定します。Runtimeには何も記述していません。

prt_03_accel

1F目と2F目の結果を並べて表示してみました。
おお、accelerationて揮発的なアトリビュートなんですね。っていう言い方が適切かはわかりませんが、つまり1Fごとに値がリセットされる、ということです。
継続して値を持たせたいのであれば毎フレーム設定し続けないとだめ。
ExpressionでやるならばRuntimeを使う必要があるということです。
Fieldを使うと勝手にそうなるのであまり意識もしないで良いんですが。

先ほどRuntimeには何も記述していませんと述べた通り、このシーンではパーティクルが生まれた瞬間の1Fだけaccelerationを設定しています。
するとaccelerationはvelocityに作用して値を変化させた後、0にリセットされています。
accelerationを常に与えたい場合はRuntime Expressionにも何かしらの設定が必要な模様です。
Fieldを使うと勝手にそうなるので、特にこれを触る用途が思い浮かばない場合は特に覚えておく必要はないと思います。

ちなみにaccelerationは、値をFPSで割ったものがvelocityに毎フレーム追加されていきます。今回は<<0, 1.0, 0>>を与えた次のフレームのvelocityの値は<<0, 0.033, 0>>となります。

prt_04_v

値がvelocityに追加されます、と言った通り、accelerationは加速を行います。
例えばParticleにTurbulence Fieldをアサインしてそのまま再生すると、ものすごい速さで発散していった、という様なことを経験された方も少なくないと思いますが、これはaccelerationに常に値が入り、velocityに値が追加され続けた結果です。
通常はこれを防ぐためにDrag Fieldなどを使用して良い感じの結果に持って行きます。

また、Mayaではvelocityやaccelerationは秒単位の値とみなされます。
つまりvelocityが<<0, 1.0, 0>>であれば、エミットから1秒後、つまりageが1.0の時、つまり生まれてからFPS分のフレームが進んだときにY方向に1進むということです。
この秒単位というのが非常に大事で、これをイメージ出来ていないとExpressionでvelocityなどを直接いじる場合には混乱が生じがちなので要注意です。
ageも秒単位です。つまりage==1.0ならば、生まれてから1秒経っているという意味です。1F後ではありません。

秒単位で扱うのは、MayaだけでなくHoudiniなどでも同じです。
ただMaxのPFlowは確かフレーム単位だったような気が、、、?Max屋さんは要チェックです。

その3、Drag Fieldに関して。

Drag Fieldって、すげー良く使う割にはどういう基準でMagnitudeを設定すればよいのか分からないのでいつも困っていました。完全に目合わせとか勘とか、そんな感じです。
でもずっとそればっかりでも気持ち悪いので、今回はここも詳しく突っ込んでいきたいと思います。

prt_drag
(リンク先はアニメーションGifになっています。)

こちらは数値の表示の関係上、EmitterのSpeedを10.0に設定しています。
その他の設定は画像にある通りのMagnitudeでDragを適用しています。
Attenuationは0です。

当然ですが値が大きくなるほど減衰が大きくなっています。
2Fの画像を見ると、Drag 1.0のVelocityYの値は9.667です。
ドラッグのないものと比較すると0.334の差があります。
0.334という値の根拠を考えると、なんとなくVelocity/FPS(10.0/30.0)じゃないかと言う気がします。

続いて見て見ます。
3Fの画像ではDrag 1.0の数値は9.344になっています。
9.967-9.344を計算すると、0.323となり、先ほどよりも減衰の値が減っています。
現状のVelocityで再度先ほどと同じ計算をすると、9.967/30.0=0.3322333…となり、このフレームでの減衰値と一致します。

上記の計算だと1.0はどこかに行ってしまっているので、今度はDrag 0.5のパーティクルに注目してみます。
0.5の場合も見てみると、2Fでは9.833, 3Fでは9.669となります。
減衰は0.167, 0.164となっています。
Drag1.0の結果と比べておよそ半分ぐらいです。

ということは。

Dragは、 Velocity / FPS * Drag Magnitude という計算式が成り立ちそうです。

おや、もしかして大きな値をいれるとDragがぶっ壊れる理由はここにあったのか?
例えばFPSが30の場合、DragのMagnitudeに30を入れるとVelocityは0になってしまいそうです。

どれどれ。

・・・

お、すごい。
完全にVeocityが消えた。

Image converted using ifftoany

てことはこれ、さらに大きな値を入れると・・・?

ためしにFPSの倍の60をドン。
おおおお、10と-10を1Fごとに行ったり来たり。
良い感じにぶっ壊れますね。

うーむ、Dragを普通に使う場合、MagnitudeにはFPS以上の値をいれるのは危なさそうです。
ただMotion Fieldとして使う場合はその限りではないのかもしれませんね。
Transformの値に関わって来るし、そもそもデフォルトで30とか設定してあるし。

なるほどなー。
勉強になります。

最後にざっくりその4.FieldのAttenuationに関して。

これは以前調べたもので、あれこれ画面キャプチャとかもしていないのでExpressionだけ乗せます。

FieldのAttenuationに関しては以下のExpressionで凡そ出来ました。

vector $p = particleShape1.position;
float $d = mag($p);
float $di = $d+1.0;
float $f = pow(1.0/$di, particleShape1.attenuation) * particleShape1.magnitude;
particleShape1.acceleration = <<0, $f, 0>>;

上記はFieldが原点にあると仮定して計算したものなのですが、どのフィールドでどういう過程でやったのか忘れてしまいました:p
でも確かvelocityの値を見ながらやったのでまぁ凡そ合っているはず、、です、、、
間違ってたらすみません。ある程度確認はしてたと思うんですが、、

ともあれ、Attenuationってほとんどデフォルトで値入ってる割には結果がイメージ出来なくてだいぶ使いづらいし、そもそも減衰なのに範囲の指定さえ出来ないとかどうなの??と思ってたんですが、この式見てたぶん一生使う機会ないかもな、と再認識しました。
個人的にはこれは非常に使いづらいパラメータです。

とりあえず今後もまだまだMaya使う機会が多そうなのでこの辺もちらほら念頭に置きながら日々お仕事をこなして行こうと思います。

こういうのって必要ないといえば必要ないんですけど、迷ったときには良い基準になってくれるので個人的にはやれるときにやっておきたいと常々思っています。

何か間違いなどあればご指摘頂けると大変助かります。
よろしくどうぞ。

“[maya] 超今更ですがパーティクルの基礎的な部分のリサーチ” への2件のフィードバック

  1. 確かに、Attenuationってよくわからなくて使いづらいよね。
    ってか、自分で式にしたのは偉いw。
    以前遊びでFieldプラグイン作った時は、サンプルのtorusField.cppからコピペしました。

    torusField.cpp 522行目
    double force = magValue * (pow((1.0-(distance/maxDist)),attenValue));

    俺もコレ見てなるべく値を入れないようにしてますw。

  2. >Co,さん
    おお、torusFieldにAttenuationの式乗ってたんですね。
    凡そ同じにも見えますが、torusFieldの方は明示的にmaxDist入れられる様になってるみたいですね。
    これであればだいぶ使いやすいんですが、、、
    MayaのサンプルPluginってなんか公式と違う式をしれっと使ってたりするので怖いなと、以前思ったことがあるんですが、、、ていうかなんでこっちを標準にしないのADさん、、、

コメントを残す

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