Fluids & reaction

Smoothed Particle Hydrodynamics

SPH

近傍粒子をカーネルで重み付けし、密度や力を推定して流体を計算する。

5 / 10

Interactive demo

Preparing the demo…

Smoothed Particle Hydrodynamics

Drag to orbit, Ctrl/⌘ + scroll to zoom. Use two fingers on touch screens.

This explanation is currently available in Japanese.

ひとことで

流体をたくさんの小さな粒子の集まりとして表し、各粒子の密度や圧力を「近くの粒子を、距離に応じた重み(カーネル関数)で足し合わせる」ことで求めて動かす方法です。格子が不要で、水しぶきや、流れが分かれたりくっついたりする動きを自然に扱えるため、水を使うゲームや、流体パズルでよく使われます。

ゲームでの使いどころ

  • 水や液体のゲーム:『Sprinkle』や『Where's My Water?』のような水を導くパズル、ポーションや溶岩が流れる演出。
  • 飛び散る液体:水しぶき、血しぶき、スライムの飛沫など、粒子がばらけて飛ぶ表現。
  • 少量の液体:コップの水、噴水、水たまりなど、狭い範囲の液体。広い海には向きません。
  • GPU で大量に:近傍探索を GPU で行えば数十万粒子も扱え、NVIDIA FleX などのミドルウェアで使われてきました。

しくみ

カーネルによる推定

SPH(Smoothed Particle Hydrodynamics)の基本は、ある場所の量 AA を、周りの粒子 jj の値に重み WW を掛けて足し合わせて推定することです。

A(x)≈∑jmj Ajρj W(∣x−xj∣,h)A(\mathbf{x}) \approx \sum_j m_j\,\frac{A_j}{\rho_j}\,W(|\mathbf{x} - \mathbf{x}_j|, h)

WW はカーネル関数と呼ばれ、距離 0 で最大、影響半径 hh で 0 になる釣り鐘形の関数です。特に密度は、単に周りの粒子の質量を重み付きで足すだけで求まります。

ρi=∑jmj W(∣xi−xj∣,h)\rho_i = \sum_j m_j\,W(|\mathbf{x}_i - \mathbf{x}_j|, h)

粒子の動かし方

  1. 密度を求める:上の式で各粒子の密度を計算します。
  2. 圧力を求める:密度が基準の密度 ρ0\rho_0(水なら 1000 kg/m³)より高ければ、押し広げる圧力を与えます。例えば p=k(ρ−ρ0)p = k(\rho - \rho_0)、より硬い水には Tait の式 p=B((ρ/ρ0)7−1)p = B\big((\rho/\rho_0)^7 - 1\big) を使います。
  3. 力を求める:圧力の勾配(押しのける力)と、粘性(周りと速度をそろえる力)を、カーネルの勾配を使って近くの粒子から集めます。
fi圧力=−∑jmj pi+pj2ρj ∇W(xi−xj,h)\mathbf{f}^{\text{圧力}}_i = -\sum_j m_j\,\frac{p_i + p_j}{2\rho_j}\,\nabla W(\mathbf{x}_i - \mathbf{x}_j, h)
  1. 動かす:重力も加えて、半陰的オイラー法などで速度と位置を更新します。

ゲーム向けの安定化

素直な SPH は、水を縮みにくくしようと圧力を強くすると、非常に小さな時間刻みが必要になります。ゲームでは、Clavet らの「予測・緩和」方式(2005)がよく使われます。粒子をいったん速度で動かしてから、混みすぎた粒子同士を位置で直接押し離し、動いた量から速度を求め直すことで、大きな時間刻みでも安定します。さらに「近距離の密度」に反発する項を加えて、粒子が 1 か所に固まるのを防ぎます。デモはこの方式です。

実装のポイント

  • 近傍探索が主役:各粒子は影響半径 hh 以内の粒子としかやり取りしないので、空間を hh の大きさのマスに分け(空間ハッシュ)、隣の 9 マス(3 次元なら 27 マス)だけを調べます。これをしないと粒子数の 2 乗の計算になります。
  • 粒子の間隔と影響半径:影響半径は粒子の間隔の 2 倍程度にし、1 粒子あたり 20〜40 個(3 次元)の近傍が入るようにします。
  • 表面の描き方:粒子を球で描くと粒々に見えます。画面上で粒子の深度をぼかして滑らかな水面にする(スクリーンスペース流体)、またはマーチングキューブで表面メッシュを作ります。

つまずきやすい点

  • 圧縮されやすい:圧力を弱くすると水がぶよぶよ縮み、強くすると時間刻みを細かくしないと爆発します。この板挟みを解くために、PBFや IISPH などの方法が作られました。
  • 粒子の固まり(テンサイル不安定):圧力が負になる所で粒子同士が引き合い、団子状に固まります。負の圧力を 0 に切る、近距離の反発を加える、などで防ぎます。
  • 壁際の密度不足:壁の向こうには粒子がないので、壁際の粒子は密度が低く計算されます。壁の中に動かない粒子(境界粒子)を並べて補います。

デモで試すこと

  1. 左に積まれた水の柱が崩れ、波となって右の壁にぶつかり、跳ね返って、やがて平らな水面になります。「ダムを崩す」でくり返せます。
  2. 「粒子の色」を「密度(混み具合)」にすると、底のほうの粒子ほど押しつぶされて密度が高い(明るい)ことが分かります。
  3. 「圧力の強さ」を下げると、水が縮みやすくなって沈み込み、ぶよぶよした動きになります。左下の「平均の密度」も基準より大きくなります。
  4. 「近距離の反発」をオフにすると、粒子が団子状に固まりやすくなります。水槽の中をドラッグすると、棒で水をかき混ぜられます。

References

GPU Gems — Fast Fluid Dynamics Simulation on the GPU ↗

A general reference for this subcategory.