ひとことで
流体をたくさんの小さな粒子の集まりとして表し、各粒子の密度や圧力を「近くの粒子を、距離に応じた重み(カーネル関数)で足し合わせる」ことで求めて動かす方法です。格子が不要で、水しぶきや、流れが分かれたりくっついたりする動きを自然に扱えるため、水を使うゲームや、流体パズルでよく使われます。
ゲームでの使いどころ
- 水や液体のゲーム:『Sprinkle』や『Where's My Water?』のような水を導くパズル、ポーションや溶岩が流れる演出。
- 飛び散る液体:水しぶき、血しぶき、スライムの飛沫など、粒子がばらけて飛ぶ表現。
- 少量の液体:コップの水、噴水、水たまりなど、狭い範囲の液体。広い海には向きません。
- GPU で大量に:近傍探索を GPU で行えば数十万粒子も扱え、NVIDIA FleX などのミドルウェアで使われてきました。
しくみ
カーネルによる推定
SPH(Smoothed Particle Hydrodynamics)の基本は、ある場所の量 を、周りの粒子 の値に重み を掛けて足し合わせて推定することです。
はカーネル関数と呼ばれ、距離 0 で最大、影響半径 で 0 になる釣り鐘形の関数です。特に密度は、単に周りの粒子の質量を重み付きで足すだけで求まります。
粒子の動かし方
- 密度を求める:上の式で各粒子の密度を計算します。
- 圧力を求める:密度が基準の密度 (水なら 1000 kg/m³)より高ければ、押し広げる圧力を与えます。例えば 、より硬い水には Tait の式 を使います。
- 力を求める:圧力の勾配(押しのける力)と、粘性(周りと速度をそろえる力)を、カーネルの勾配を使って近くの粒子から集めます。
- 動かす:重力も加えて、半陰的オイラー法などで速度と位置を更新します。
ゲーム向けの安定化
素直な SPH は、水を縮みにくくしようと圧力を強くすると、非常に小さな時間刻みが必要になります。ゲームでは、Clavet らの「予測・緩和」方式(2005)がよく使われます。粒子をいったん速度で動かしてから、混みすぎた粒子同士を位置で直接押し離し、動いた量から速度を求め直すことで、大きな時間刻みでも安定します。さらに「近距離の密度」に反発する項を加えて、粒子が 1 か所に固まるのを防ぎます。デモはこの方式です。
実装のポイント
- 近傍探索が主役:各粒子は影響半径 以内の粒子としかやり取りしないので、空間を の大きさのマスに分け(空間ハッシュ)、隣の 9 マス(3 次元なら 27 マス)だけを調べます。これをしないと粒子数の 2 乗の計算になります。
- 粒子の間隔と影響半径:影響半径は粒子の間隔の 2 倍程度にし、1 粒子あたり 20〜40 個(3 次元)の近傍が入るようにします。
- 表面の描き方:粒子を球で描くと粒々に見えます。画面上で粒子の深度をぼかして滑らかな水面にする(スクリーンスペース流体)、またはマーチングキューブで表面メッシュを作ります。
つまずきやすい点
- 圧縮されやすい:圧力を弱くすると水がぶよぶよ縮み、強くすると時間刻みを細かくしないと爆発します。この板挟みを解くために、PBFや IISPH などの方法が作られました。
- 粒子の固まり(テンサイル不安定):圧力が負になる所で粒子同士が引き合い、団子状に固まります。負の圧力を 0 に切る、近距離の反発を加える、などで防ぎます。
- 壁際の密度不足:壁の向こうには粒子がないので、壁際の粒子は密度が低く計算されます。壁の中に動かない粒子(境界粒子)を並べて補います。
デモで試すこと
- 左に積まれた水の柱が崩れ、波となって右の壁にぶつかり、跳ね返って、やがて平らな水面になります。「ダムを崩す」でくり返せます。
- 「粒子の色」を「密度(混み具合)」にすると、底のほうの粒子ほど押しつぶされて密度が高い(明るい)ことが分かります。
- 「圧力の強さ」を下げると、水が縮みやすくなって沈み込み、ぶよぶよした動きになります。左下の「平均の密度」も基準より大きくなります。
- 「近距離の反発」をオフにすると、粒子が団子状に固まりやすくなります。水槽の中をドラッグすると、棒で水をかき混ぜられます。