This explanation is currently available in Japanese.
ひとことで
雲、霧、煙、爆発の炎のように、表面を持たず空間を満たしている「もや」を描く方法です。画素ごとに視線を飛ばし、一定の歩幅で少しずつ進みながら、各地点の密度と、そこで散乱されて目に届く光を積み重ねていきます。進むほど後ろの景色は見えにくくなり(透過率が下がり)、途中の霧が光って見えます。
ゲームでの使いどころ
- 空の雲:『Horizon Zero Dawn』『Microsoft Flight Simulator』『レッド・デッド・リデンプション 2』などの立体的な雲は、ボリュームレイマーチングで描かれています。
- 霧・もや・砂嵐:地面を這う霧、洞窟の湿気、砂漠の砂嵐。
- 煙・爆発:流体シミュレーションの結果(3D テクスチャの密度)を描く。
- 魔法・エネルギー体:内部が渦巻く光の球、ポータル、オーラ。
しくみ
視線上の位置 での密度(消散係数)を とすると、そこまでに光が弱まる割合(透過率)はビール・ランバート則で表せます。
目に届く光は、途中の各地点で散乱された光を、そこまでの透過率で弱めて足し合わせたものです。
これを一定の歩幅 の和で近似するのがレイマーチングです。各地点では、
- 密度 を調べる(ノイズの雲、3D テクスチャなど)
- その地点に届く光を求める:光源の方向へも短く進み、途中の密度から自己影を計算する
- 光の散乱方向の偏り(位相関数)を掛ける
- 「この区間で散乱されて届く光」を足し、透過率を 倍に下げる
透過率が十分小さくなったら(奥がもう見えない)、そこで打ち切れます。
実装のポイント
- 開始位置をずらす(ジッター):歩幅が粗いと、同じ深さで標本を取る画素が並んで縞模様(バンディング)になります。画素ごとに開始位置を乱数でずらすと、縞が細かいノイズに変わり、時間方向に平均(TAA)すると消えます。
- 低解像度で描く:ボリュームは重いので、画面の 1/4〜1/16 の解像度で描いて拡大したり、毎フレーム一部の画素だけ更新したりします。
- 空白を飛ばす:密度 0 の領域は、境界ボックスや距離場で大きく飛ばします。
- 区間内の積分:散乱光を で足すと、密度が高いときに明るくなりすぎます。区間内で積分した を使うとエネルギーが保たれます(Frostbite の改良)。
つまずきやすい点
- 負荷が大きい:画素数 × 歩数 × 影の歩数 だけ密度を評価します。デモの設定でも 1 画素あたり数百回です。
- 不透明な物体との前後関係:ボリュームの中に物体がある場合は、深度バッファを読んで、物体の手前で打ち切る必要があります(ボリューメトリックフォグのデモはそうしています)。
- 自己影の歩数:影の歩数を減らすと、雲の内部の陰影が単調になります。影には粗い密度(低い解像度のノイズ)を使う工夫があります。
デモで試すこと
- 「視線方向の歩数」を 6〜10 まで下げ、「開始位置を画素ごとにずらす」をオフにすると、雲に縞模様が出ます。オンに戻すと縞がざらつきに変わります。
- 「太陽方向の自己影」をオフにすると、雲の内部が一様に明るくなり、立体感が失われます。
- 水色の点は、雲を横切る 1 本の視線上の標本点です。歩数を変えると間隔が変わります。
- 「雲の濃さ」を上げると、奥の景色が見えなくなり、内部の陰影も濃くなります。