今回はCurlノイズを使用したパーティクルの制御についてのおはなしです。
CurlノイズはPerlinノイズをベースにしたランダムノイズ関数で 適用することでパーティクルをあたかも流体計算をしているように振る舞わせることができます
Perlinノイズは空間座標を与えるとだいたい同じような値を返してくる特徴があって これが空間の物理特性を表現するのに都合がよく 考え方は空間にポテンシャル場 (流体のムラ)が存在しそれによって、移動するパーティクルの速度変化が影響を受けるというシュミレーションです。
そういえば先日 光子の速度に影響するヒッグス粒子が発見されましたね イメージはあんなふう
流体といえばナビエ・ストークス方程式(Navier-Stokes)をもとにしたシュミレーションを耳にしたことがあるかと思います。3DCGでセルグリッドの流体シュミレーションなどはだいたいナビエ・ストークス式をもとにした近似方程式で計算されています。 ナビエ・ストークス方程式は非常に複雑で まだ解を求めることが出来ないため。3DCG計算の分野では用途に合わせて簡易方程式を利用して計算を行うことで計算量を減らしています。
現在の流体計算はシュミレーション上はそれっぽく振る舞うので実用的にはこんなもんでいいかな というところで
おさまっているようです。
スクウェア・エニックス オープンカンファレンスレポート(前編) - GAME Watch
2年ほどまえのスライドからですが、ゲームで使用する場合グリッドベースでまじめに計算を行う場合は計算量に見合ったクオリティは得られないため それっぽく振る舞うノイズ関数を使用した流体計算のほうがコストに見合うということが語られています。 FFアグニなどもこの方法みたいですね DeepDownもそれっぽいですが
■今回の実行サンプル
● WebPlayer CurlTest.html
● UnityPackage CurlTest(131002).unitypackage
今回の場合はノイズを毎回計算してパーティクルの挙動に反映させるやりかたを考えます。参考にしたのがこのサイト
■curl noise for particles
curl noise for particles - syphobia -- the procedural way
パーティクルシステムで乱流をシュミレートする場合フレームごとに弱い力を速度に与える方法がとられます。(fig1
Unityのパーティクルシステムのアセット 例えばXeffectなどはソースも公開されていますので解析してみるとRandomで数値を加算しているだけです。
fig1:
|
|
ベクトルは−1から1で全ての角度方向をカバーできますのでこれでパーティクルの方向はコントロールできます。
そこにPerlinノイズによるゆらぎを加味することでそれらしくパーティクルの速度をコントロールします。
fig2:
|
|
パーティクルの座標をスケーリングしてPerlinノイズで(-1.0,1.0)の範囲で値を導きますz座標 にはある定数値と時間を与えてノイズフィールドを変更します。
という感じです これは自分の知ってるカールノイズなのか?という疑問もあるのですが それっぽければ良いので 今回はこの記事を信用しましょう。
■コードの解説
●"ParticleBufferAccess_Curl.cs"
|
using UnityEngine; int length = particleSystem.GetParticles(particles); while (i < length) { particles[i].position += new Vector3(dx[i]*Amount.x, dy[i]*Amount.y, dz[i]*Amount.z) ; } |
particleSystemからGetParticlesでパーティクルの構造体を取得して 計算したものをparticleSystemにSetParticlesで書き込みます
データ更新にはLateUpdate()を使用します パーティクシステムはフレーム単位で更新されますが データが確定してから処理をしないと更新のタイミングが合わずにうまくいかないためです。
Unityのランタイム関数 Mathf.PerlinNoise
■Procedural Examples By Unity Technologies, Free
http://u3d.as/content/unity-technologies/procedural-examples/3zu
"Crumple mesh modifier"のコードを参考にしてPerlinノイズからパーティクルの速度を計算する本体を記述したのが以下の部分です。
| float scalex = Time.time * speed + 0.1365143f; particles[i].position += new Vector3(dx[i]*Amount.x, dy[i]*Amount.y, dz[i]*Amount.z) ; |
時間あたりのスケールコントロールがspeed でscalexyzにそれぞれ加算される数値 x: 0.1365143f, y: 1.21688f, z: 2.5564f はマジックナンバーのようなのでそのまま使用します。
サンプルのコード(fig2:)ではposition.z は式に定義していませんが 今回のコードでは計算に加味しています。
このPerlin関数は(0,1)の値を返す関数なのですが(Unityの2DPerlinも同じ範囲の値を返す) サンプルのコード
ではPerin関数が(−1,1)の値を返してくるという前提だと思いますので 同じような式にしたい場合はperlinノイズに perlin(***)*2-1 の補正をかけて拡張すればよいかと思います。
式によって若干パーティクルの挙動に変化が出ると思いますが、もともとが正確な計算でもないので用途に応じてそれっぽい飛び方をするように最適化すればいいような気がします。
さらに大量にパーティクルを処理させたい場合は Perlinノイズ生成部分を3Dテクスチャ化またはハッシュテーブルを使用したものに置き換えたり、GPUシェーダやコンピュートシェーダの使用 などが有効そうです。
データの調整ですがScale 値がPerlinノイズのサイズに対する数値の取得範囲だと考えてください。
ノイズテクスチャに対して値が小さければパーティクルは大きく動き 大きければ小刻みに振動します。
だいたい良い感じに調整したつもりなんですけどね。
スクリプトはデータの流れがわかりにくくなるのでベタな書き方をしていますが 変数を構造体でまとめたり わかりやすく最適化をしてみてください。
その他 使用法についてはPackageファイルをダウンロードして確認してみてください。
■参考
■Introduction To Noise Functions
http://freespace.virgin.net/hugo.elias/models/m_perlin.htm
パーリンノイズの生成方法とコードが掲載してあるサイトがありますので興味のある方は参照して理解を深めてみてください
■Noise-Based Particles, Part I at The Little Grasshopper
●Noise-Based Particles, Part I http://prideout.net/blog/?p=63
●Noise-Based Particles, Part II http://prideout.net/blog/?p=67
流体シュミレーションでは有名?なThe Little Grasshopperブログですがノイズベースパーティクルの構造が
把握できると思います。
●GPU Gems - Chapter 5. Implementing Improved Perlin Noise
●GPU Gems - Chapter 38. Fast Fluid Dynamics Simulation on the GPU


