Interactive Indirect Illumination Using Voxel-Based Cone Tracing(2)

前回に引き続き、Pacific Graphics 2011で発表された論文を見ていきます。

This article is based on the following publication.
[Interactive Indirect Illumination Using Voxel Cone Tracing]
http://maverick.inria.fr/Publications/2011/CNSGE11b/
All of this publication's contents that are used in following this article are belong to the original authors.

1. Introduction

先のポスターとほぼ同様なので省略。

2. Previous Work

省略。

3. Algorithm overview

先のポスターとほぼ同様なので省略。

4. Our hierarchical voxel structure<

先のポスターとほぼ同様なので省略。

4.1 Structure description


基本的には先のポスターに書いてあったとおり。 M=3という比較的小さなBrickを採用した場合、内包空間の値を正しく補間するために、 ボーダーになるBrickを外周に余分に持たなければならないが、Mの値が小さくなるにつれて、ボーダーが全体に占める割合が増加する。 これを避けるために、末端ノードが内包する空間が、Brickが内包するvoxelの中心より内側に収まるようにすることで、これを軽減する。これにより、ボーダーのvoxelを設けるよりも、半分以下のメモリ使用量で実装できる。このメモリ使用量の低減により、neighbor pointerを追加することが可能になり、空間的に隣接するノードに、 簡単にアクセスすることが可能になる。このリンク構造は直接光をvoxel treeに格納する際に非常に重要である。

4.2 Interactive voxel hierarchy construction and dynamic updates

ポリゴンベースのシーンのvoxel化を素早く行うために、 voxel hierarchyの構築には、GPUのラスタライゼーションを使う。 大きなシーンの構築に対応するために、その過程で一様なvoxelを構築することをしない。 octreeを直接構築する。この過程を高速に処理するために、 シーンを、静的なものと動的なものに分けて処理する。ただし同じoctreeを使用する。 タイムスタンプをこの二つを区別するために用いる。これにより静的なオブジェクトが毎フレーム デストラクトされることを防止する。

4.2.1 Octree building

まずはじめにGPUのラスタライゼーションを用いてoctreeを作る。 ラスタライズはシーンの3つの主軸に従って3回行う。viewportの解像度はoctreeの最大解像度に対応する。 たとえば5123ならば512×512でラスタライズする。 depthテストはdisableにすることで、最低1回のpixel shaderスレッドが、存在するvoxelのために起動される。 各スレッドはoctreeをtop-to-bottomでトラバースして、必要があればその場で直接分岐させる。 自分に対応する末端ノードにたどり着けば、texture color, nromal, materialをストアする。
実際にノードを分岐する際、2x2x2のサブノードを事前確保されたnode bufferから確保する。 確保したサブノードのアドレスを’child’ポインタ格納し、該当スレッドは下層のノードの処理を引き続き行う。 node bufferの確保には、global sharedのインクリメントカウンタを用いる。
pixel shaderスレッドのような、高度に並列実行されるケースでは、 複数のスレッドが同じノードの分岐を行い、octreeの一貫性が保たれないケースがある。 ノードごとのmutexを使用できれば一貫性を保つことは可能だが、いまのところ、他のスレッドがノードの分岐を終えるまで、他のスレッドを休止して待たせることは不可能である。
active waiting loop(分岐が終わるまで、atomicを読み続けて、ポーリングする)を避けるために、 global thread listを導入する。中断されたスレッドは自分自身の情報をここにストアしておく。 global thread listは後ほど(論文内ではvertex shader)再実行してoctreeにストアする。 この再実行により、新たにglobal thread listが生成されるかも知れないが、これが空になるまで、再実行を繰り返す。 末端voxelに格納される値は、対応するBrickのvoxelに直接格納される。 Brickの確保はノードの確保と同様に、shared brick bufferから行う。
これらの作業にはOepnGL拡張の NV_shader_buffer_load NV_shader_buffer_store を用いることで実現されている。 これらがCUDAのようなビデオメモリ上のポインタ機能の実現や、アトミックオペレーション機能をOpenGLシェーダー内で提供している。(現在は、DX11のShaderModel5.0相当でも同様の機能が提供されているはずである。)

4.2.2 Dynamic update

動的オブジェクトによるoctreeの更新も、先に説明したラスタライゼーションを用いた手法を用いる。 違いとしては、動的オブジェクトによって生成されるvoxelは、静的オブジェクトで作成されたvoxelを上書きしないことである。静的オブジェクトのノードとBricksの上書きを避け、素早いクリアを行うため、これらのelement(nodeとBricks?)はバッファの最後尾にストアれる。

4.2.3 MIP-mapping


先の項で作成したoctreeは、MIP-map化されなければならない。このフィルタリング作業は、n階層に対してn-1回で行われる。それぞれのステップで、実行スレッドは、サブノードが保持するBrickの情報をフィルタリングして生成する。 フィルターする際は、先の項で定義したように、vertex-centered voxelなので、端のvoxelが隣接するBrickにかぶっている。フィルターする際は隣接するvoxelに値を平均化して分散させる必要がある。論文の例では33のGaussian kernelを使用している。

4.3 Voxel representation

各々のvoxelは下位レベルvoxelののライトの振る舞いを表現しなければならない。最終的にはシーン全体を表さなければならない。 そのために、法線情報と光源方向情報の分布を格納するのに、Gaussian lobeによるモデル化を適用する。 異方性のないGaussian lobeに値を格納することとする。 Gaussian lobeは平均化されたベクトルと、その標準偏差で表現される。 補間作業を簡単にするために、Gaussian lobeの分散は、そのベクトルの長さで表現することとする。Gaussian lobeのベクトルをDとするとその分散は下記のように表される。

これによるライトの演算は第7項で取り扱う。
これらに加え、遮蔽情報も概算する。遮蔽情報は、voxel内情報の単純化のため、ひとつの平均化された値でストアされる。 これによって、方向情報を欠落し、薄いオブジェクトに対する適用性が低下することになる。 マテリアルカラーは不透明度を乗算した色の値を格納する。これは第7項に説明する演算のためである。 法線情報には、遮蔽情報を考慮するために、あらかじめ不透明度が乗算される。

5. Approximate Voxel Cone Tracing


大域照明は一般的にたくさんのrayのサンプリングを必要とする。これらのrayは空間的、方向的に一貫性がある。 この一貫性に関する考え方を利用して、voxel cone tracingを導入する。 オリジナルのcone tracing[CNLE09]は、複雑で処理時間もかかるが、フィルターされたvoxel階層を用いることで、 すべての光束を一度に概算することができる。 これはcone axisに沿ってconeの半径に応じたレベルのvoxelを参照することで実現する。 この間、quadrilinear interpolationを用いることで、エイリアシングが発生することを防ぐ。 このフィルター化されたvoxelデータを利用することで、元来のcone tracingとは異なる結果となるが、 それらしい結果を得ることが出来る。
cone tracingの間、値の積算に、[Max95, EHK04]で解説されている、emission-absorption optical modelを採用している。 遮蔽度αと、cone方向に反射された光のカラーCを追跡する。(カラーは題7項で) 各々のステップで、適切にフィルターされた、遮蔽項α2と、カラーC2をサンプリングし、 front-to-back(サンプリングは手前からだが、奥から順にブレンディング)になるように値の更新を行う。

この演算の過程で、品質を向上させるため、連続したサンプリングの間隔d’は、サンプリングするvoxelのサイズdと一致しないので、これを補正する。

6.Ambient Occlusion


このcone tracingと、この論文内の間接照明アルゴリズムについての理解を助けるために、最初に単純なケース、 すなわちAOの概算について説明する。 AOはサーフェース上の任意の点Pにおいて、遮蔽項を半球状に積分したものである。遮蔽度αを距離による減衰関数f(r)で減衰させたもので計算することでAOを計算することが出来る。 この論文の実装では減衰関数f(r)1/(1+λr)(λは定数)を使用している。
AOの半球積分を効率的に行うため、半球をいくつかの範囲に分割し、それらをconeに見立てる。 これらのconeごとの加算を半球積分とすれば、各々のconeを先のAOの減衰関数f(r)を用いてcone tracingし、 その結果を累算することで、AOの概算とすることが出来る。

Final Rendering
このAOの結果をレンダリングの結果に適用するため、この演算をpixel shaderで行う。 効率的に行うためにdeferred renderingを用い、カメラからworld position, surface normalを描画し、 これらを用いてAOを計算する。

まだまだ途中です。
ただ、voxelをどのように構築するかは分かった気がします。でもなんで3度もレンダリングするのでしょうか。DepthTestをdisableにしたら、視体積に入ったプリミティブはすべてラスタライズの対象になるので、voxelizeしようとする空間がorthgonalならば1回のラスタライゼーションでいいはずなのですが。

続きはまた今度。

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中