This explanation is currently available in Japanese.
ひとことで
ノイズで作った「ポテンシャル場」の回転(curl)を速度として使う手法です。回転をとった場は数学的に発散がゼロになるため、粒子は渦を巻きながら流れても、特定の点に吸い込まれたり湧き出したりしません。流体を解かずに「それらしい煙の流れ」を安く得られるのが最大の魅力です。
ゲームでの使いどころ
- 魔法・オーラ・霊体のエフェクト:キャラクターの周りをまとわりつくように漂う粒子。発散がないので、時間がたっても粒子が一点に固まらず見た目が崩れません。
- 焚き火や煙突の煙:上昇速度にカールノイズを足すだけで、まっすぐな柱が渦を巻く煙になります。
- ホタル・胞子・雪の舞い:ランダムな揺らぎより「空気の流れに乗っている」感じが出ます。
- GPU パーティクルの標準部品:Unity VFX Graph や Unreal Niagara の「Curl Noise Force」は、ほぼこの手法そのものです。
しくみ
ベクトル場 の発散 は「その点から流れが湧き出す量」を表します。発散が正なら湧き出し、負なら吸い込みです。非圧縮の流体(煙や水)では発散がゼロなので、粒子の密度は流れても変わりません。
どんな滑らかなベクトル場 でも、その回転の発散は恒等的にゼロになります。
そこで、3 つの独立したノイズ を並べてポテンシャル場とし、その回転を速度にします。
偏微分は中心差分で近似するのが簡単です。ノイズの解析的な微分が得られる実装(simplex noise の導関数版など)を使えば、評価回数を減らせます。
2D なら話はさらに単純で、スカラーのノイズ から を作るだけです。これは等高線に沿って流れる速度になります。
実装のポイント
GPU パーティクルの速度更新で使う GLSL の例です。snoise は任意の 3D ノイズ関数です。
- 周波数(渦の大きさ)と強さは独立に調整できるようにしておくと、アーティストが扱いやすくなります。
- 時間変化はノイズの入力座標をずらして作ります。ずらす速さが速すぎると流れが「ちらつく」ので、上昇速度より十分遅くします。
- 障害物をよけさせたい場合は、ポテンシャル場を障害物の近くで 0 に近づけると、流れが表面に沿って回り込みます(Bridson らの論文の主題です)。
つまずきやすい点
- ノイズをそのまま速度にしない:3 つのノイズ値をそのまま に使うと発散を持つ場になり、粒子が吸い込み点に集まってダマになります。デモの「ノイズをそのまま使う」で確認できます。
- 厳密な流体ではない:滑らかな連続場のカールは発散ゼロですが、差分近似や時間積分の誤差でわずかに崩れます。また、圧力や密度を解く流体シミュレーションではないので、物体に押されて煙がよける、といった双方向のやり取りは表現できません。
- 評価コスト:差分で求めると 1 粒子あたりノイズを 18 回評価します。粒子数が多いならコンピュートシェーダーで計算するか、解析微分つきのノイズを使います。
デモで試すこと
- 「場面」を箱いっぱいの粒子にし、速度場を切り替えて「最も混んだ区画 / 平均」の数値を比べてください。カールノイズでは 1 倍前後に保たれ、ノイズをそのまま使うと時間とともに数値が増えていきます。
- 「渦の大きさ」を小さくすると、細かい乱流のような煙になります。
- 「速度場の矢印」を表示すると、水平断面での流れの向きが見えます。カールノイズの矢印は渦を描き、湧き出し・吸い込みの形が現れないことに注目してください。