距離場・暗黙形状

符号付き距離場

Signed Distance Field / SDF

表面までの距離と内外で形を表す。

1 / 10

インタラクティブデモ

デモを準備しています…

符号付き距離場

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

ひとことで

空間のあらゆる点に「いちばん近い表面までの距離」を割り当て、形の内側では符号を負にした関数(または、その値を並べたデータ)です。値が 0 になる場所がちょうど形の表面になります。ポリゴンのように面を並べて形を表すのではなく、「どこでも距離を答えられる関数」として形を表すのが特徴です。

f(p)={− 表面までの距離p が内側− 0p が表面上+ 表面までの距離p が外側f(\mathbf{p}) = \begin{cases} -\,\text{表面までの距離} & \mathbf{p}\ \text{が内側}\\ \phantom{-}\,0 & \mathbf{p}\ \text{が表面上}\\ +\,\text{表面までの距離} & \mathbf{p}\ \text{が外側} \end{cases}

ゲームでの使いどころ

  • 形そのものを描く:レイマーチングで SDF を直接描く(デモシーン、『Dreams』や『Claybook』のような粘土・造形ゲーム)。
  • ソフトシャドウとアンビエントオクルージョン:Unreal Engine の Mesh Distance Fields は、メッシュから焼いた SDF で遠くまで柔らかい影や遮蔽を計算します。
  • 当たり判定・パーティクルの衝突:「その点は内側か」「表面まであと何 m か」「どちら向きに押し出せばよいか」が 1 回の評価で分かるので、大量の粒子を複雑な地形に当てるのに便利です(GPU パーティクルの衝突など)。
  • 文字や UI:文字の形を SDF で持つと、拡大してもぼやけず、縁取りや光彩も安く描けます(MSDF)。
  • 地形の編集:ボクセル地形で掘る・盛るといった編集を、距離の値の足し引きで表します。

しくみ

基本形の SDF は短い式で書けます。球なら中心からの距離から半径を引くだけです。

f球(p)=∥p−c∥−rf_{\text{球}}(\mathbf{p}) = \lVert \mathbf{p} - \mathbf{c} \rVert - r

箱は、各軸で表面からどれだけはみ出しているかを使って、外側では角までの距離、内側では最も近い面までの距離(負)を返します。

q=∣p∣−b,f箱(p)=∥max⁡(q,0)∥+min⁡(max⁡(qx,qy,qz), 0)\mathbf{q} = |\mathbf{p}| - \mathbf{b},\qquad f_{\text{箱}}(\mathbf{p}) = \lVert \max(\mathbf{q}, 0) \rVert + \min\big(\max(q_x, q_y, q_z),\, 0\big)

SDF の最も大切な性質は、値 dd を半径とする球の中には表面が 1 つもないことです。この保証があるので、

といった便利な操作が成り立ちます。また、距離 dd から一定値 rr を引く(f−rf - r)だけで、形を rr だけ太らせて角を丸められます。

実装のポイント

  • 関数で持つか、テクスチャで持つか:少数の基本形なら式で評価し、任意のメッシュは 3D テクスチャに距離を焼き込みます(ボリュームテクスチャの各ボクセルに距離を保存)。焼き込んだ SDF は解像度の分だけ細部が失われます。
  • 移動・回転は逆変換で:形を動かすときは、形ではなく評価する点 p\mathbf{p} のほうを逆向きに動かします。回転や平行移動は距離を変えないので、SDF の性質が保たれます。拡大縮小は、座標を ss で割ってから評価し、結果に ss を掛け戻します。
  • 符号の規約:内側を負にするのが一般的ですが、ツールやエンジンによっては逆のこともあります。テクスチャに保存するときは、0.5 を表面として 0〜1 に写すことが多いです。

つまずきやすい点

  • 「距離らしい値」と本当の距離は違う:形を組み合わせたり変形したりすると、値が正確な距離でなくなることがあります。符号(内外)は正しくても距離が過大になると、スフィアトレーシングで表面を突き抜けます。距離が実際より小さめ(保守的)なら安全ですが、処理は遅くなります。
  • 外側の最小値は正確でも、内側は正確とは限らない:複数の形の最小値は、外側では正確な距離ですが、形が重なった内側では正確ではありません。
  • 焼き込み SDF の解像度:細い部品(ワイヤーや薄い板)は、ボクセルより細いと消えてしまいます。

デモで試すこと

  1. 「断面の高さ」を上下させると、形を水平に切った断面で、内側(青)と外側(オレンジ)の距離の縞が変わります。白い線が距離 0、つまり形の輪郭です。
  2. 緑の探査点をドラッグしてください。表示される半透明の球(半径 = 距離)は、必ずどれかの形にちょうど接し、中には何も入りません。この性質が SDF のすべての応用の土台です。
  3. 等距離線は、形から離れるほど角が取れて丸くなります。箱の角の外側では、距離は角の 1 点までの距離になるためです。

参考資料

Unreal Engine Mesh Distance Fields ↗

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