距離場・暗黙形状

メタボール

Metaballs / Implicit Surfaces

影響場の等値面から融合する液滴を描く。

5 / 10

インタラクティブデモ

デモを準備しています…

メタボール

ドラッグで視点を回転、Ctrl(⌘)+ スクロールでズーム。タッチ操作は 2 本指です。

ひとことで

たくさんの「塊」がそれぞれ周囲に影響の場を広げ、その合計がしきい値を超える範囲を表面とする形の表し方です。2 つの塊が近づくと間の場が足し合わされてしきい値を超え、自然に橋がかかって融合します。離れると再び分かれます。溶岩ランプ、水滴、スライム、血しぶきのような、くっついたり離れたりする液状の表現によく使われます。

F(p)=∑iw ⁣(∥p−ci∥Ri),表面: F(p)=TF(\mathbf{p}) = \sum_i w\!\left(\frac{\lVert \mathbf{p} - \mathbf{c}_i \rVert}{R_i}\right),\qquad \text{表面:}\ F(\mathbf{p}) = T

ゲームでの使いどころ

  • 液体の見た目:粒子で計算した流体(SPH など)の粒子をメタボールとして描き、つながった水面に見せる。
  • 2D ゲームの水・スライム:粒子をぼかした円として描いてから、しきい値で切り抜く「スクリーンスペースのメタボール」は、2D の液体表現の定番です。
  • VFX:溶岩ランプ、合体する魔法の球、粘液、雲のような塊。
  • 生き物の形:アメーバ状の敵や、粘土細工のような造形。

しくみ

影響関数 w(x)w(x) には、中心で 1、半径 RR(x=1x = 1)で滑らかに 0 になる関数がよく使われます。デモでは Wyvill 型の関数を使っています。

w(x)={(1−x2)3x<10x≥1w(x) = \begin{cases} (1 - x^2)^3 & x < 1 \\ 0 & x \ge 1 \end{cases}

範囲が有限なので、遠くの塊は計算から外せます(ブリン(Blinn)が提案した元の形は指数関数で、影響がどこまでも続きます)。

  • しきい値 TT を下げると、場の弱い外側まで表面になるので、塊は太ってつながりやすくなります。
  • しきい値を上げると、塊は痩せて離れやすくなります。

距離場との違い:FF は距離ではなく「影響の強さ」です。距離の性質(その値の球の中には何もない)がないので、スフィアトレーシングでそのまま歩幅に使えません。描画は次のいずれかで行います。

  1. 格子上で FF を評価してマーチングキューブでメッシュ化する(2D ならマーチングスクエア)
  2. レイマーチングで、小さな歩幅や距離の見積もり((T−F)/∣∇F∣(T - F) / |\nabla F| など)を使って表面を探す(デモはこの方法)
  3. 2D なら、ぼかした円を加算で描いてからしきい値で切り抜く

実装のポイント

  • 塊の数と空間分割:塊が多いと全点で全塊を調べるのは重いので、格子やハッシュで近くの塊だけを調べます。
  • 法線:場 FF の勾配の逆向きが外向き法線です。影響関数の微分は解析的に書けるので、差分を使わず正確に求められます。
  • 色の混合:各塊の色を影響の強さで重み付けして平均すると、融合部で色が混ざります。

つまずきやすい点

  • 滑らかな合成(smooth min)との混同:見た目は似ていますが、スムーズユニオンは距離場を 2 つずつ合成する方法で、メタボールは影響を全部足し合わせる方法です。メタボールでは多数の塊が集まると、場が重なって想定より大きく膨らみます。
  • 1 つだけの塊の大きさ:塊 1 つの表面の半径は RR ではなく、w(x)=Tw(x) = T となる xx で決まります(デモの設定では RR の約 6 割)。
  • メッシュ化の解像度:格子で評価する場合、塊が格子より小さいと消えたり、ちらついたりします。

デモで試すこと

  1. 溶岩ランプの中で、底で温められた塊が浮き上がり、上で冷えて沈みます。近づいた塊が融合し、離れるとちぎれる様子を観察してください。
  2. 「しきい値」を下げると塊が太ってつながりやすく、上げると痩せてばらばらになります。
  3. 「場の値を断面で表示」で、場の合計の分布と、黄色の等値線(合計 = しきい値)が表面になっていることを確かめてください。
  4. 「塊の中心と影響範囲を表示」で、影響範囲(球)が重なったところで融合が起きていることが分かります。

参考資料

Unreal Engine Mesh Distance Fields ↗

分野全体の資料で、この項目を直接扱っているとは限りません。