[GI] Japanese memo of "Rasterized Voxel-based Dynamic Global Illumination"

参照

概要



  • GPU Pro4 にあった記事を読んだのでそのメモです.
  • 一言で言うと, GPU を利用したボクセル化をする Light Propagation Volume(LPV) です.
    • ボクセル化は SVOGI (Sparse Voxel Octree Global Illumination)と同様に GPU のラスタライザを使った方式で行います.
    • ライトの書き込みは RSM ではなく, ライト単位でボクセルに対する長方形への書き込みで行います.
    • 伝搬と間接光計算は Light Propagation Volume の方式で行います.
  • 間接光の計算結果は RGB の Spherical Harmonics の (0,1 次) として, 32x32x32 の解像度のボクセルに書き込まれます.
    • RGB の SH(0,1)次には 3 * 4 = 12 個のパラメータが必要です.
    • そこで, half float の RGBA の 2D テクスチャアレイ が 3 枚で対応します. ( 4 * 3 = 12 )
    • これの解像度が 32x32 ピクセルにし, 配列数を 32 にすることで 32x32x32 の解像度のボクセルを表現できます.
      • ※ ここでは何故か 3D テクスチャを使っておらず, トライリニア補間するためにシェーダ内で 2D テクスチャアレイをリニアブレンドしています.
    • 以下, 大まかな処理の流れです.

(0) シーンのボクセル化

  • SVOGI と同様に GPU のラスタライズの機能を使って, シーンのポリゴンをボクセル化します.
  • ポリゴンを XYZ の 3 軸のうち, 射影面積が大きな方向をジオメトリシェーダで選択してから, Atomic で排他制御をしながら構造化バッファ(RWStructuredBuffer)に対して書き込みます.
  • Voxel の構造体の要素は以下のようになっています.
struct VOXEL
{
    uint  colorMask;   // エンコードされたカラー
    uint4 normalMasks; // エンコードされた法線
    uint  occlusion;   // 0 より大きな時はボクセル化されたことを示している.
};

(1) ライト情報の書き込み

  • ライトごとに, 32x32x32 のボクセルに対してライト情報の書き込みを行います.
    • 具体的には32x32 の解像度の長方形を描画して, そのライトの影響範囲に応じたスライスの個数分だけインスタンス描画します. ( 最大で 32 スライス分のインスタンス描画 )
  • どのスライスに対して書き込みを行うか?についてはジオメトリシェーダを使って選択します.
    • もしこの機能が使えない場合, 毎回, 32 スライス分のインスタンス生成をする必要があります.

(2) ライトの伝搬

  • Light Propagation Volume と基本的には同様の方法で, 自分の XYZ 軸方向に対して近傍にある 6 ボクセルに対してライトの情報の伝搬処理を全体に対して 2 回行います.
    • 1 回目の伝搬処理では最初にライトを伝搬させておくため, ボクセルの有無による遮蔽処理を行わずに行います.
    • 2 回目の伝播処理ではライトリークを防ぐために, ボクセルの有無によるライトの伝搬の遮蔽処理を考慮します.
  • また この伝搬処理についてはコンピュートシェーダで行います.

(3) 間接光の計算

  • ここでは, ライトの情報を結果を書き込んだボクセルを参照して間接光を求めます.
    • 具体的には例えば全画面の長方形を描画して, そのピクセル単位でデプスバッファからワールド座標を復元します.
    • そして, それをボクセルでの座標表現に対してマッピングして, そのワールド座標に相当する SH 係数を取得します
    • 最後に, そのピクセルの法線を法線バッファから取得してSH 係数を展開することで, その法線方向にあったディフューズ間接光を求めます.
  • (デプスバッファと法線バッファが必要になりますので, ディファードシェーディングとは相性が良いです.)