"Fast, Stencil-Based Multiresolution Splatting for Indirect Illumination" の概要

洋書"GPU Pro"の記事 "Fast, Stencil-Based Multiresolution Splatting for Indirect Illumination" を読みましたので, その概要について書きます.

  • "Fast, Stencil-Based Multiresolution Splatting for Indirect Illumination". Chris Wyman, Greg Nichols, Jeremy Shopf. GPU Pro. 2009.

この記事は Reflective Shadow Maps による間接照明の計算を改良した技法を紹介したものなので, 以前に紹介した以下の3つの論文を読んでおくことをお勧めします.

"Multiresolution Splatting for Indirect Illumination"の概要 - OLD hanecci’s blog : 旧 はねっちブログ は, 以下のレンダリング手順から構成されていました.

  1. Reflective Shadow Maps (RSM) の構築
  2. RSM からの VPL の抽出
  3. カメラ位置からの直接光を使ったレンダリング
  4. VPLごとに, フルスクリーンの"splat" を複数の解像度を持つバッファ(illumination buffer)に対して描画する.
  5. illumination buffer の組み合わせ・アップサンプリング・補間
  6. 直接光・間接光を使ったレンダリング結果の組み合わせ

"Multiresolution Splatting for Indirect Illumination"の概要 - OLD hanecci’s blog : 旧 はねっちブログ では, 深度と法線の不連続性をチェックしながら, フルスクリーンの splat を geometry shader によって再帰的に分割した splat を生成して, 複数の解像度の illumination buffer のうち適切な解像度のバッファに対して描画しています. この手法の欠点は, この splat の再帰的な分割によって, geometry shader に対して負荷がかかってしまうことです.

そこで, この記事 "Fast, Stencil-Based Multiresolution Splatting for Indirect Illumination" では, フラグメントシェーダで適切な解像度の illumination buffer を選択する処理を行い, その結果をステンシルバッファに書き込んでおきます. そして, ステンシルバッファの結果に基づいて, VPL ごとに間接光の計算を行います. この手法では, 適切な解像度の illumination buffer を選択する処理をフラグメントシェーダで行っていますので, フラグメント単位で並列化することができます.

"Multiresolution Splatting for Indirect Illumination"の概要 - OLD hanecci’s blog : 旧 はねっちブログ では, 複数の解像度を持つバッファ(illumination buffer)をそれぞれ別々のテクスチャとして確保していました. 例えば, 128x128, 256x256, 512x512, 1024x1024 の4枚のテクスチャを確保したりします.

この記事の方法では, 各解像度の illumination buffer を収めた1枚のテクスチャとして確保します. 例えば, 1024x2048 のテクスチャ1枚を確保して, 内部に各解像度の illumination buffer(1024x1024, 512x512, 256x256, 128x128)を敷き詰めるようにします. このとき, 1枚のテクスチャに敷き詰めて illumination buffer 以外の領域は, 余白とします. そして, この1枚のテクスチャと同じサイズの splat を描画して, フラグメントシェーダでそのフラグメントが (余白ではなく) illumination buffer にあるかどうかや, そのフラグメントが VPL による間接光の照明計算をするのに適切な解像度であるどうかのチェックを行い, そうであるときにはステンシルバッファをチェックしておきます.

そして, チェックしておいたステンシルバッファに相当する pixel に対して, VPL による間接光の計算をおこないます. 擬似コードで書くと, こんな感じになります.

ParallelEarlyStencilBufferTest()

pixel_list = FullScreenQuad()
vpl_list = SampledVirtualPointLights()

for vpl in vpl_list:
  for pixel in pixel_list:
    if ( FailsEarlyStencilTest(pixel) ):
       continue
    IlluminatePatchFromPointLight( pixel, vpl )

最後に, "Multiresolution Splatting for Indirect Illumination"の概要 - OLD hanecci’s blog : 旧 はねっちブログ と比較して, この記事による手法では, この記事の結果によると, 5〜10倍 描画速度が速くなるみたいです. やはり, VPL の間接光の計算をする適切な解像度の illumination buffer を選択する処理を, フラグメントシェーダによって並列化しているのが効いているのだと思います.