GPU Gems2 : High-quality Global Illumination Rendering Using Rasterization の説明

概要

  • この記事では GPU Gems2 に載っていた GPU を使ったファイナルギャザリングの計算について簡単に説明します.

導入

1 パスでのグローバル・イルミネーションの計算方法
  • 実装にレイトレーシングのみを使う方法です.
  • レイが表面にぶつかったらそこから再帰的にレイを飛ばして, その点に入射する光を計算する方法です.
  • 利点は仕組みや実装がシンプルなことで, 欠点はレイが表面を反射するたびに指数関数的にレイの本数が増えるので処理が重いことです.
2 パスでのグローバル・イルミネーションの計算方法
  • 1 パス目でフォトンマップやラジオシティを使って, 粗くグローバル・イルミネーションの結果を近似的に求めておきます.
  • そして, 2 パス目でファイナルギャザリングを行い, 1 パス目の結果を効率的に使って最終結果をレンダリングします.
  • 利点は 1 パス目のものよりも速いこと, 欠点は 2 パス目のファイナルギャザリングが重いことや, 実装が複雑になったり調整するパラメータが増えることです.
疎なファイナルギャザリング結果の補間による高速化
  • 全ての点でファイナルギャザリングすると処理が重いので, ファイナルギャザリングを計算する点を疎に分布させて, 点間の値については補間して利用する高速化の方法があります.
  • しかし欠点として, シーンが複雑なときには必要な疎なサンプル点の数が意外と多くなったり, あるいはアーティファクト対策のために非直感的なパラメータを調整する必要があることです.

本題の内容

GPU によるファイナルギャザリング
  • ファイナルギャザリングとは下図のように, ある点に対して入射する光を計算するためにその点の法線を中心とした半球状にレイを飛ばし, そのレイと衝突した表面の放射輝度を取得する方法です.


  • この研究では GPU を使ってファイナルギャザリングの計算を高速化する方法について紹介しています.
  • この方法の利点は(レイトレーシングで使う)高速にレイトレーシングするための空間データ構造が不要であることです.
  • そして, ファイナルギャザリングを計算するサンプル数を調整するだけなのでパラメータの調整がシンプルです.
  • また必要に応じてファイナルギャザリングを計算するサンプル点を増やせるので, プログレッシブにレンダリングすることもできます.
Global Ray Bundle による GPU でのファイナルギャザリングの計算
  • 通常のファイナルギャザリングの計算時には下図の(a)のように各点ごとに, 半球状にレイを飛ばします.
  • 今回の GPU を使ったファイナルギャザリングではその方法とは異なり, 下図(b) のように1 回の計算で同じ方向のレイの束を計算することを繰り返します.
  • これを Global Ray Bundle と言います.


Depth Peeling
  • 次に今回の GPU でのファイナルギャザリングに必要な Depth Peeling について簡単に説明します.
  • Depth peeling は GPU でデプスバッファを使って, ポリゴンの層を順に抽出する手法です.
  • 下図が Depth Peeling で青い平面上に載っている Teapot のシーンに対して, Depth Peeling した結果で, 手前のレイヤーから奥に向かって Layer0, Layer1, Layer2, Layer3 となっています.


  • Depth Peeling のアルゴリズムは以下のようになっています.
  • 1. デプスバッファを 2 枚用意して, それぞれを最大のデプスの値(1.0)で初期化しておきます.
  • 2. そして, あるカメラ視点からシーンを描画する際に 1 枚目のデプス値よりもデプス値が遠い時だけ, 2 枚目のデプスバッファに書き込む処理を行います.
  • 3. この処理を繰り返すことで, あるカメラ視点からシーンを見た際の奥のデプスのレイヤーから順に取り出すことができます.
Depth peeling を利用した Global Ray Bundle の計算
  • 下図のようにあるサンプル点から 1 方向にレイを飛ばした時に, 最初にぶつかる点の色を求めたいとします.


  • これは Depth peeling で順にデプスのレイヤーを取り出す際に, サンプル点をカメラ空間に対して射影した点を元にサンプリングしたデプスのレイヤーが奥側にあるときだけ, その色を保存しておけば求めることができます.
  • レイの 1 方向分の Depth peeling の際に, 各サンプル点ごとにこの処理を行なっておけば, 最終的に全てのサンプル点から 1 方向のレイを飛ばした際に最初にぶつかる点の色を求めることができます.
GPU のファイナルギャザリングの用のテクスチャの準備
  • 最初に GI を計算したい点のサンプル数を求めます.
  • もし頂点単位で間接光を計算したい場合はこれがシーンの頂点数になります.
  • またもしライトマップとしてテクスチャに間接光を焼きたい場合にはその合計のテクセル数がそのサンプル数となります.
  • そして, そのサンプル数だけ以下のリソースを準備します.
  • GPU ファイナルギャザリング用のテクスチャ
    • pos_texure : float3 テクスチャ(ワールド位置座標 * サンプル数)
    • normal_texure : float3 テクスチャ(ワールド法線 * サンプル数)
    • color_texure : カラーテクスチャ (RGB * サンプル数)
    • gi_texure : カラーテクスチャ (RGB * サンプル数)
Depth Peeling 用のレンダリングバッファの準備
  • 次に, Depth Peeling 用のレンダリングバッファとして以下のものを用意しておきます.
  • Depth Peeling 用のレンダリングバッファ
    • depth_buffer : デプスバッファ (シーンの Depth peeling 時のデプス)
    • cmp_depth_buffer : 比較用のデプスバッファ
    • color_buffer : カラーバッファ(シーンの Depth peeling のときのカラー情報)
GPU でのファイナルギャザリングの手順
  • 1. GI を計算したい点のサンプルで, pos_texture と normal_texture を初期化します.
  • 2. depth_buffer0 と depth_buffer1 を 1.0 (最も遠い距離)で初期化します.
  • 3. color_buffer を黒色(0.0, 0.0, 0.0)で初期化します.
  • 4. Depth peeling を利用した Global Ray Bundle の 1 方向分の計算を, 1 層分の Depth Peeling 分だけ行います.
  • 5. pos_texture の各位置座標をシーンをレンダリングしたカメラ空間に対して射影して, 該当する箇所の deph_buffer の値と color_texture の値を読み込み, それをレイの衝突点の候補とします. カメラ視点から見て, このレイの衝突点の候補が pos_texture の位置座標よりも奥側にあるときに, その衝突点の候補は間接光の計算に必要と考えられるので, この衝突点の候補の color_buffer の値を, color_texture に書き込んでおきます.
  • 6. Depth Peeling を 1 層分進めるために, シーンを描画して結果を depth_buffer と color_buffer に書き込んでおきます. その際に, デプステストについては通常とは反転させ(手前ではなく, 奥側のときだけデプステストに合格), また cmp_depth_buffer よりも奥側にある場合はカリングします.
  • 7. depth_buffer を cmp_depth_buffer にコピーします.
  • 8. (Global Ray Bundle の 1 方向分の Depth peeling を最後まで終わらせるために,) 6. でのレンダリングするフラグメントの数が 0 になるまで, Step 5. に戻ります.
  • 9. color_texture の結果を gi_texture に書き込みます.
  • 10. 必要な Global Ray Bundle の回数分だけ, 2. に戻ります.

応用

GPU で完結したグローバル・イルミネーションの計算
  • この研究は 2 パスのグローバル・イルミネーションの計算方法なので, 1 パス目で CPU によるフォトンマップやラジオシティを使って, 粗くグローバル・イルミネーションの結果を近似的に求めておく必要があると言いました.
  • しかし, この 1 パス目では GPU による直接光によるディフューズライティングを計算しておき, 下図のように繰り返して間接光の計算を行うことで最終的に GPU のみで完結してグローバル・イルミネーションを計算することができます.


参考文献