KickstartRT の処理・構造を理解する

先日 KickstartRT デモを動作させる手順を記載しましたが、このデモアプリケーションを通じて KickstartRT がどのような構造で処理をしているのかを追いかけてみたいと思います。あくまで個人で追いかけた内容ですので間違っている可能性も大いにあります。もし、そこは違うよということであれば教えて頂けたら幸いです。

KickstartRT の役割

KickstartRT の役割は、レイトレーシング機能を活用して反射、Global Illumination、Ambient Occlusion、影などの情報を生成することです。そのために、アプリケーションからジオメトリの情報(頂点バッファ・インデックスバッファ)を受け取って、KickstartRT 内部で BVH 情報の構築を行います。通常の描画時においては、アプリケーション側で生成した G-Buffer のテクスチャやコマンドバッファを入力として渡します。 アプリケーション側から提供されるコマンドバッファに対して、コマンドを書き込む仕様であり、コマンドバッファの Open/Close も行わないとのことです。

このような構造にすることで、アプリケーション側はレイトレーシングのことは意識せず、描画フローの大きな変更をすること無く組み込めるようになっています。

KickstartRT の構造

  • TaskContainer クラス
  • ExecuteContext クラス

上記のクラスを足がかりにして処理を追いかけてみます。

まずは ExecuteContext を用意する必要があり、ExecuteContext::Init 関数で KickstartRT 側にコンテキストを生成してもらいます。そして CreateTaskContainer 関数で TaskContainer を生成します。

kickstartRT では GPU で何かの演算・処理するものを Task と表現しており、BVHを処理するタスクとして GeometryTask、InstanceTask、BVHBuildTask があり、レンダリング関連として DirectLightingInjectionTask、 TraceSpecularTask、TraceShadowTask、デノイズ用として DenoiseSpecularTask、DenoiseDiffuseTask などがあります (一部のみ列挙しました、実クラスにはもっと多くの種類があります)。

BVHタスク

GeometryTask、InstanceTask は、BLAS/TLAS のようなもののようです。この BLAS/TLAS を構築するために BVHBuildTask を発行する、という流れのようです。

GeometryTask では頂点バッファ・インデックスバッファを入力として BLAS を保持するという役目のようですし、まさにレイトレーシングパイプラインにおけるBLAS相当と考えることが出来そうです。

描画用タスク

DirectLightingInjection

2Dテクスチャとして与えられたダイレクトライティングバッファを KickstartRT SDK 側が管理する DirectLightingCache に書き込むタスクです。このキャッシュはワールドスペースで構築されているらしいです。

TraceTasks

レイトレーシングを実行するタスクで、KickstartRT 側で構築した BVH情報を使用します。入力として与えられた GBuffer を参照し、各表面をレイトレースの起点として使います。

DenoiseTask

デノイズ用のタスクです。レイトレーシングで得られた結果をデノイズします。このとき NVIDIA の NRD ライブラリを活用します。

処理の流れ

デモアプリケーションをキャプチャしたものが次の図です。前半はシャドウマップを生成、GBufferの生成をしていたりとなっています。後半にはブルームやトーンマップの処理、デバッグGUIなどの描画を行っています。

この中間付近で色付けされていない部分がありますが、ここが KickstartRT の処理している部分となります。覗いてみると、コンピュートシェーダーによる計算やレイトレーシングパイプライン呼び出しなどが観測されます。

DirectLightingCache の効果

DirectLightingCache の動きっぽいものが見えたので、紹介します。これは床面を鏡面反射にしています。スクリーンに映っていない部分の反射も頑張って実現しているようですが、荒くポリゴンフェイス単位というか、ブロック状の単色塗りのようなものが観測されます。

少し視点を動かして画面内で描画されたあとは、キャッシュの効果か繊細な描画結果になっていきます。しかし、キャッシュの範囲から外れると再び上記のようなブロック状の結果に戻ってしまうようです。

しかし、ラフネスを0ではなく、すこし上げてあげると私には気にならなくなるくらいになりますので、問題にはならないのかもしれませんね。(このあたりは、もんしょさんも呟かれていた記憶があります)

DirectX11 について

KickstartRT のデモアプリケーションは DirectX11 の描画モードを選択できましたし、KickstartRT にも DirectX11 のサポートいう文字が見えたので気になっていました。調べてみると、DirectX11 API を使用しているアプリケーションに組み込める、という意味合いであり、 DirectX11 のみで使用できるという訳ではありませんでした

KickstartRT 内部では DirectX12 Raytracing (DXR) の機能を使ってレイトレーシングを実行する必要があります。そのため、レイトレーシングハードウェアが使えない場合には本機能を使うことは無理と考えられます。

なぜ、DirectX11 で結果を使えるのか、というと DirectX リソースを共有ハンドル・共有リソースという仕組みを用いて双方向での利用を実現していました。特に DirectX11 ではドライバが処理する部分が多いため、リソースのタイミング制御にフェンスを使って配慮が必要なことが分かります。

まとめ

KickstartRT がどのように処理をしているのかについて大まかに追いかけてみたものを紹介しました。また、個人的に一番の興味対象だった DirectX11 での実現方法について謎がとけたので記載しました。

KickstartRT の重要ポイントである(と私は思っている) DirectLightingCache のバッファ構造などはまだ未だに分かっていないポイントであり、どなたかの説明に期待したいところです。

DirectLightingCache による着色

そういえば、非RTX シリーズでもコンピュートシェーダーによるレイトレーシングがドライバ内でサポートされている環境がありますが、そちらでも動くのでしょうか。手元にそのような環境がないため、動作については未確認です。

参考

今回の内容は各リポジトリのドキュメントに書かれていることを参考にして、コードを追いかけてみたり実行を追いかけてみたりしたものです。それぞれのドキュメントがしっかりと書かれているので確認されると良いかと思います。

関連記事

コメントを残す

メールアドレスが公開されることはありません。

CAPTCHA


このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください