This explanation is currently available in Japanese.
ひとことで
符号付き距離場で表された形を、画面の各画素から視線(光線)を飛ばして描く方法です。光線上の今いる点で距離 を測り、その距離だけ一気に前進することを繰り返します。距離 の球の中には何もないことが保証されているので、飛び越えても何にもぶつかりません。表面に近づくほど歩幅が小さくなり、距離がほぼ 0 になったところが表面です。レイマーチングの中でも、距離場を使って歩幅を決める方式を特にスフィアトレーシングと呼びます。
ゲームでの使いどころ
- 距離場で作った形を描く:デモシーンや Shadertoy の作品、造形ゲーム、特殊な VFX(ワープゲート、液体、フラクタル)。
- 影と遮蔽:Unreal Engine の距離場ソフトシャドウや距離場 AO は、光源や周囲に向けて同じ要領で距離場をたどります。途中で最も表面に近づいた度合いから、半影の柔らかさも得られます。
- 当たり判定:弾や視線がどこで壁に当たるかを、距離場に対するレイキャストとして求められます。
- 雲・霧の描画の高速化:ボリュームのレイマーチングで、何もない空間を距離場で一気に飛ばす(空白スキップ)。
しくみ
光線の起点 、向き 、進んだ距離 として、次を繰り返します。
終了条件は 3 つです。
| 条件 | 意味 |
|---|---|
| 表面に到達した | |
| 何にも当たらず遠くへ抜けた | |
| 反復回数が上限に達した | 表面をかすめ続けている(縁や浅い角度) |
何もない空間では距離が大きいので数歩で遠くまで進み、表面の近くでは歩幅が自動的に細かくなります。ポリゴンの交差判定のように形ごとに特別な計算をする必要がなく、距離関数さえあれば、どんな形でも同じループで描けます。
反復回数が増えるのは、物体の縁をかすめる光線(距離が小さいまま横に進む)と、床や壁を浅い角度で見る光線(表面と平行に進むので歩幅が縮む)です。
実装のポイント
- ε を距離に比例させる:遠くの物体は画面上で小さいので、1 画素より細かい精度は不要です。 とすると遠景の反復が減ります。
- 歩幅を縮める・伸ばす:距離場が厳密でない(変形や滑らかな合成を使った)ときは、歩幅に 1 未満の係数を掛けて踏み越えを防ぎます。逆に 1 より大きく進んで踏み越えたら戻る「過剰緩和(over-relaxation)」で高速化する方法もあります。
- 深度を書き込む:通常のメッシュと混ぜて描くときは、当たった点の深度を計算して書き込むと、前後関係が正しくなります(このデモもメッシュの矢印や球と混在しています)。
- 法線:当たった点の距離場の勾配を差分で求めます(距離場の勾配法線)。
つまずきやすい点
- 歩幅が距離より大きいと突き抜ける:デモの「歩幅の倍率」を 1 より大きくすると、表面を飛び越えて内側に入ってしまうことがあります。距離場が正確でない場合も同じことが起きます。
- 反復の上限に達した画素:縁の画素で上限に達して「当たらなかった」扱いになると、輪郭に穴や光の筋が出ます。上限に達した場合も、その時点で十分近ければ当たりとみなすなどの対処をします。
- 画面全体に適用すると重い:1 画素ごとに数十〜数百回の距離評価をするので、複雑なシーンでは負荷が大きくなります。何もない領域を境界ボックスで飛ばす、低解像度で描いて拡大するなどの工夫をします。
デモで試すこと
- 「1 歩ずつ再生」で、視点から伸びる光線が、円(その地点の距離)の分だけ前進していく様子を見てください。箱の上をかすめるところで円が小さくなり、歩数が増えます。
- 黄色の目標点をドラッグして光線の向きを変え、何もない方向に向けると、数歩で遠くへ抜けることが分かります。
- 「歩幅の倍率」を 1.5 以上にすると、表面を踏み越えることがあります(結果の表示が「表面を踏み越えた」になります)。
- 「画面全体の反復回数を色で表示」をオンにすると、物体の縁と、床を浅い角度で見る遠方が明るくなります。これが負荷の集中する場所です。