DirectXの話 第128回

Voxel-Ray Tracing

前回やってみたVoxelizationを利用してレイトレーシングをやってみました。

オブジェクトの描画は普通のラスタライズですが、リフレクションをVoxel-Ray Tracingで計算してみました。

オブジェクト自体を動かすようにしてませんが、ライトは変更できるようになっています。

これには理由があるんですが、その辺はあとで説明します。

このサンプルにはいくつかの問題があり、それが上記の原因ともなっています。

この問題の対応方法についてはある程度考えていますが、速度面の問題も出るのでどうするのが一番かは何とも言えないところです。

それらもあとで説明します。

さて、レイトレーシングはだいぶ昔から存在するレンダリング技法ですが、まだまだリアルタイムで使用するには問題がある技術です。

レイトレーシングは通常の描画手法としては画面の各ピクセルに対してカメラからレイ(方向を持った直線)を飛ばし、オブジェクトとの衝突判定、及びマテリアル計算を行います。

レイトレは画面解像度が上がることで計算量が増えます。また、衝突を取る回数などでも計算量が増えてしまい、その結果として現在でもリアルタイム技術としては微妙な状態にあります。

しかし、GPGPUの登場により、描画の一部をレイトレで行うことも現実的なレベルになってきていると思います。

例えばシャドウイング、リフレクション、グローバルイルミネーションなどですね。

今回のレイトレーシングはポリゴンモデルとレイの衝突判定ではなく、Voxelとレイの衝突判定を取ります。

Voxelizeは前回のサンプルから少し変更を行っています。

前回は3Dテクスチャにカラーを保存していましたが、今回はStructuredBufferにカラーと法線を格納しています。

格納方法はただの上書きですが、この方法では結果が安定しません。

ポリゴンの描画タイミングは常に変化するため、Voxelizationの結果が変化してしまうわけです。

今回はそのまま公開していますが、次回以降は安定する方法に変更する予定です。

とはいえ、速度面の不安が…

次にレイトレーシングの処理ですが、render_final.hlslのTraceRayToVoxels()関数がそれです。

2種類存在していますが、1つは『GPU Pro 3』の”Ray-traced Approximate Reflections Using a Grid of Oriented Splats”から拝借した簡易版です。

こちらは簡易版のため、衝突判定が不正確ですが、その分少々高速です。

2つめはこちらのサイトの"A Fast Voxel Traversal Algorithm for Ray Tracing"からおこしたものです。

こちらの衝突判定はかなり正確で、基本はこちらを用いています。

ただ、リフレクションに使用する分には前者でも割と見た目に問題が無く、高速な手法が必要であれば前者を利用するのもありかと思います。

また、高速化のためリフレクションのレイは長さを限定しており、衝突判定が打ち切られて正常な結果になりません。

サンプルではカメラを床に這わせるようにするとリフレクションのオブジェクトが切られてしまうのが確認できると思います。

さて、最初の段落で問題があると書きましたが、Voxelizeの不安定さは問題の1つです。

また、単純な上書き描画の場合は最初にバッファをクリアする必要があります。

3Dテクスチャの1ピクセルに格納される情報が大きければバッファのクリアだけでもかなり時間がかかってしまいます。

これを回避する方法として考えられるのは、以前やってみたOrder Independent Transparencyと同様のリンクリストを用いる方法です。

この方法であれば1ピクセルの情報量が増えたとしても1ピクセルにつき4バイトのバッファコピーで済みます。

そして同一ピクセルに対して複数のポリゴンによる情報も持たせることが可能で、Atomic命令自体も軽いものだけで済みます。

しかし問題も存在します。

1ピクセルの複数の情報を一旦マージする必要があります。

カラーをブレンドするとか、代表値を取り出すとかですね。

これを行わないと衝突判定が取られた際に必ずマージ作業を行わなければならなくなります。

もちろんこの方が高速になる可能性もありますので、描画する解像度やVoxelサイズなどから最適な方法を用いるべきでしょう。

もしもVoxelデータからSparse Voxel Octreeを生成する場合はその際にマージしてしまうのも良いでしょう。

まあ、この辺は次回以降の課題ですね。

ではサンプルです。

Voxelをtrueにすると前回と同じでVoxel描画が行われます。

今回はVoxel描画を毎フレーム行っているため、かなり不安定な状態になっていることがわかります。

個人的な意見としては、リフレクションは低解像度で計算し、最終描画時にバイラテラルフィルタで拡大して使用する方が良いのではないかと思います。

その方がVoxelらしさを覆い隠しやすくなると思います。

若干ぼやけた絵面になるかもしれませんが、リフレクションならその方が良いでしょう。

次回はSparse Voxel Octreeを実装してみたいです。