This explanation is currently available in Japanese.
ひとことで
濡れた路面、磨かれた床、水たまりへの映り込みを、描き終えた画面の色と深度だけを使って近似する手法です。反射する面の各画素から反射方向へ光線を少しずつ進め、深度バッファと比べて「画面上のどの物に当たるか」を探し、その画素の色を映します。すでに描いた画面を再利用するので、シーン全体をもう一度描く(鏡のためにカメラを反転して描き直す)よりずっと安く済みます。
ゲームでの使いどころ
- 濡れた路面・雨の夜の街:ネオンや街灯が地面に映り込む、サイバーパンクな街並み。
- 磨かれた床:大理石の床、体育館、ショールーム。
- 水たまり・水面:近くの物の映り込み。
- 金属やガラスの近景の映り込み:環境マップでは表せない、近くの物の正確な映り込み。
しくみ
- 反射させる画素の 3D 位置 と法線 を、深度と法線のバッファから求める。
- 視線を法線で反射した方向 へ、光線を一定の歩幅で進める。
- 各地点を画面に投影し、その位置の深度と比べる。光線が画面上の物の奥に入ったら、そこで当たったとみなす。二分探索で当たりの位置を細かく詰める。
- 当たった位置の画素の色を、反射として加える。
これは画面上で行うスフィアトレーシングのようなもので、距離場の代わりに深度バッファを使っています。
画面空間の限界:画面に描かれていない物は映せません。
- 画面の外にある物(カメラの後ろ、画面の端の外)
- 手前の物に隠れた物の裏側
- 画面に映っている物の見えていない面
光線が画面外に出たり、当たる物がなかったりした場合は、反射をなめらかに消して、環境マップの反射で補うのが一般的です。
実装のポイント
- 画面の端でなめらかに消す:当たった位置が画面の端に近いほど反射を弱めると、画面外で反射がぷっつり切れるのが目立たなくなります。
- 粗さへの対応:粗い面では反射をぼかす必要があります。粗さに応じて光線の方向をばらつかせ、時間方向に平均するのが現代的な方法です。
- 厚みの仮定:深度バッファには表面しかないので、物の奥行き(厚み)を仮定して、当たりかどうかを判定します。
- [フレネル](/keywords/graphics/lighting/fresnel/):浅い角度ほど反射を強くすると、濡れた路面らしくなります。
つまずきやすい点
- 反射の消失:カメラを下に向けると、映るべき物が画面外に出て反射が消えます。これが SSR の最大の弱点で、プレイヤーにも気づかれやすい問題です。
- ちらつき:歩数が少ないと、細い物を飛び越えて反射が途切れたり、ちらついたりします。
- 負荷:画素ごとに数十回の深度の読み込みが必要です。低解像度で計算することが多いです。
デモで試すこと
- 濡れた床に、ネオン、柱、像、球が映り込んでいます。「SSR なし」と比べると、空間の雰囲気が大きく違います。
- 「反射だけ」で、床のどこに何が映っているかを確認してください。
- 視点を下に向けたり回したりすると、画面外に出た物は映らなくなり、反射が途切れます。「画面の端でなめらかに消す」をオフにすると、途切れ方がはっきり分かります。
- 「光線の歩数」を減らすと、遠くの物が映らなくなったり、映り込みがちらついたりします。