graphics.hatenablog.com

技術系テクニカルアーティストのあれこれ

Deferred Rendering for Current and Future Rendering Pipelines

前回の記事を読み返してて思ったんだけど、
Intel のやつ理解してないとたぶん意味不明。。
なんでそっちも軽く書いてみる。

Deferred Rendering for Current and Future Rendering Pipelines

Andrew Lauritzen
Beyond Programmable Shading, SIGGRAPH Courses 2010

Intel の研究紹介ページ
http://software.intel.com/en-us/articles/deferred-rendering-for-current-and-future-rendering-pipelines/


これ自体は、わりといろいろ詰め込んだ技術デモとその詳解なんだけど、ここで取り上げるのは Compute Shader を使ったライトのカリングについて。一言でいうと、スクリーンスペースをちっちゃいタイルに分割して、そのタイル部分に影響するライトだけをレンダリングしていく、というもの。デモではシーン中に 1024 個のライトを置いてるんだけど、これをタイルごとに分割すると、ライト数がかなり少なくなってるのがわかる。

読むべきソースコードは、App.cpp と ComputeShaderTile.hlsl の2つ。
基本的な流れは、

  1. 1タイル1スレッドグループに設定して Compute Shader を駆動
    • App.cpp:645, ComputeShaderTile.hlsl:53
    • 1タイルは16x16ピクセル
    • 1スレッドグループは16x16スレッド
  2. タイルの位置と大きさを計算して、そのタイルが担当する領域(フラスタム)を求める
    • ComputeShaderTile.hlsl:72-145
    1. (MSAA使ってて1ピクセルあたり複数サンプルが割り当てられてるから)ピクセル内でのminZ/maxZを計算:72-87
    2. タイル内でのminZ/maxZを計算:99-112
    3. タイルの大きさと位置を計算:121-123
    4. カメラ行列を使ってフラスタムを計算: 125-145
  3. すべてのライトについて、そのフラスタム領域を照らしているかどうか判定
    • ComputeShaderTile.hlsl:147-165
    • スレッドグループ全体で計算を分担してる、ループのインデクスに注意
      • 1タイルに16x16のスレッドがあるから、1スレッドあたり1024/(16*16)=4個の判定を担当
  4. 照らしていると判定されたライト(のインデクス)を記録
    • ComputeShaderTile.hlsl:162-163
  5. 記録されたライトだけをレンダリング
    • ComputeShaderTile.hlsl:171-

タイル単位だったりピクセル単位だったり(MSAAの)サンプル単位だったりいろんな粒度の処理が混ざってて、しかも自前でMSAAもやっててだいぶ複雑になってるけど、カリングの処理自体はわりとシンプルっぽい。このコードを読むときは、処理の粒度とMSAAにさえ気をつけておけば、Compute Shader 自体にはあまりさわったことがなくても、なんとなく読めると思う。