Vulkan Raytracing を少し勉強してみて感じたことを記録しています。これから始める人や悩んでいる人の助けになれば幸いです。
自分は DirectX Raytracing (DXR) をそこそこ触った後で VkRay を始めましたが、細かいところが色々と違っていますね。考え方そのものは同じようにできるので、情報の多い方でまず学習しておくのはよさそうです。
VkRay は拡張機能であること
現時点においては、 VkRay は Vulkan の拡張機能であることから、vulkan-1.lib に関数実体はありません。そのため、初期化時点で拡張機能を有効とした後で、処理関数を動的に取得するという方法が必要となります。ちょっと手間が掛かりますね。
レイのペイロードについて
意外と気付かない、見落としそうな点として、レイのペイロード変数の宣言時点での指定です。
- rayPayloadEXT
rayPayloadInEXT
このように並べると違いに気付きますが、単独でコード上で出現すると、この “In” を見落とします。実際に自分は見落としをして、データが渡らない、と苦戦することがありました。 GLSL での varying 変数, in/out 変数などで対応とることに慣れている人にとっては問題ない点かもしれません。
マテリアルを分けること
各オブジェクトごとにマテリアルを分けて描画する、といった状況での話です。単純にディフューズやスペキュラなど、テクスチャを不要な状態では簡単でしたが、テクスチャを使おうとすると少々事前準備が必要でした。
DXR と違い、各シェーダーテーブルのエントリに、テクスチャへの参照を記録することができないためです(現時点では。将来的に変わるかも?)。各エントリに固有で書き込めるデータは各バッファへのデバイスアドレスや、数値データなどになっています。テクスチャを単なるバッファとして扱い、自力でサンプリングさせるのであれば可能と思いますが、オブジェクトにテクスチャを貼りたいという場合においては、相当手間になってしまうポイントと思います。
これらを解決するためには、通称バインドレスと呼ばれる方法を使います。 Vulkan の拡張の名前としては descriptor indexing という名前です。動的なインデックス値を用いて参照するディスクリプタを決める仕組みですね。 Vulkan 1.2 のコア機能に入っているのでレイトレを実行する環境では問題なく使えます。レイトレの勉強・実装の前に、この方法を習得しておくとよいです。
Nsingt Graphics でキャプチャできないとき
VkRay のプログラムを作って、何かおかしいときには NVIDIA の Nsight Graphics を用いて調査するのが近道だったりします。しかし、キャプチャで失敗することがたまに起こります。特に vkCmdTraceRaysKHR を実行すると情報が得られないなど、出遭うことがありました。このときには、自分の書いたプログラムのどこかがおかしいと疑うことがから始めましょう。
自分の経験としては、まず以下の点を疑うのが良いかと思います。
- シェーダーはちゃんと読み込めているか
- シェーダーバインディングテーブル(SBT) のバッファは正しく確保されているか
- SBT に正しいシェーダーハンドルを正しく書き込めているか、アライメントは守れているか
- デバイスアドレスで指定しているデータは正しいアドレスを書き込めているか
- デバイスアドレスで指定したバッファへのアクセス範囲は正常であるか
また、Vulkan SDK に付属している Validation Layer を有効化し、警告情報が出ているのであればそれも取り切っておきましょう。
DXRとは違うので注意
DirectX Raytracing (DXR) ではできたことが、Vulkan Raytracing ではできないことがあります。そのため、 DXR は分かっているから VkRay も簡単に移植できる・すぐに使えるようになる、というのは、やや危険です。確かに理解の助けにはなるのですが、仕様上できないこともあるので、このような場合には注意しましょう。