🌋

VK_KHR_ray_tracing_position_fetchの使い方

2023/08/06に公開

この記事はレイトレ合宿9アドベントカレンダーの記事です。前の記事はgamさんObject Space Raymarching in Unreal Engine 5.2です!

VK_KHR_ray_tracing_position_fetch とは?

VK_KHR_ray_tracing_position_fetchVulkan 1.3.250.1 で追加されたレイトレーシングの新しい拡張機能です。ヒットシェーダにおいて、ヒットしたポリゴンを構成する3つの頂点の位置を組み込み変数として提供してくれるという機能です。

従来の問題点

レイトレーシング拡張機能では、頂点バッファとインデックスバッファから Acceleration Structure (AS) と呼ばれるデータ構造を事前に作成しておき、描画時にはASに対してレイを飛ばすことで描画します。

ASには頂点位置データが含まれていますが、いままでシェーダからアクセスする方法はありませんでした。そのため、ヒットしたポリゴンのインデックスであるgl_PrimitiveIDをもとに、以下のように位置を取得していました。

// vertexBufferとindexBufferを用意しておく
// ...
uint triIndex0 = indexBuffer[firstIndex + gl_PrimitiveID*3 + 0];
vec3 vertPos0 = vertexBuffer[triIndex0];

これで動作はするのですが、ASに含まれる頂点位置データとは別に、頂点バッファとインデックスバッファを用意しておかなければなりません。そのため、頂点位置データを二重に保持する必要がありました。

拡張機能による対応

VK_KHR_ray_tracing_position_fetch拡張機能によって、ASからヒットしたポリゴンを構成する頂点位置データを、組み込み変数gl_HitTriangleVertexPositionsEXTとして取得できるようになります。これにより、ASをビルドした後は頂点バッファとインデックスバッファは破棄できるようになります。

NVIDIAの対応ドライバ

NVIDIAのVulkan beta driver (Windows 531.83, Linux 525.47.22)で対応済みです。

使い方 ‐ Vulkanでの準備

まず、Vulkan 1.3を指定したうえで、VK_KHR_ray_tracing_position_fetchデバイス拡張機能を有効化します。

vk::ApplicationInfo appInfo;
appInfo.setApiVersion(VK_API_VERSION_1_3);
	    
const std::vector deviceExtensions{
    // ...
    VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME,
    VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME,
+   VK_KHR_RAY_TRACING_POSITION_FETCH_EXTENSION_NAME,
};

次に、物理デバイスのvk::PhysicalDeviceRayTracingPositionFetchFeaturesKHR機能を有効化します。

vk::StructureChain<vk::DeviceCreateInfo,
                   vk::PhysicalDeviceBufferDeviceAddressFeatures,
                   vk::PhysicalDeviceRayTracingPipelineFeaturesKHR,
-                  vk::PhysicalDeviceAccelerationStructureFeaturesKHR>
-    createInfoChain{createInfo, {true}, {true}, {true}};
+                  vk::PhysicalDeviceAccelerationStructureFeaturesKHR,
+                  vk::PhysicalDeviceRayTracingPositionFetchFeaturesKHR>
+    createInfoChain{createInfo, {true}, {true}, {true}, {true}};

ASのビルド時には、vk::AccelerationStructureBuildGeometryInfoKHRに対して、AllowDataAccessフラグを追加します。

vk::AccelerationStructureBuildGeometryInfoKHR buildGeometryInfo;
buildGeometryInfo.setType(type);
buildGeometryInfo.setFlags(
    vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace | 
+   vk::BuildAccelerationStructureFlagBitsKHR::eAllowDataAccess);
buildGeometryInfo.setGeometries(geometry);	

これで準備完了です。

使い方 ‐ GLSLでのアクセス方法

シェーダ側ではGL_EXT_ray_tracing_position_fetch拡張機能を有効化します。

  #version 460
  #extension GL_EXT_ray_tracing : enable
+ #extension GL_EXT_ray_tracing_position_fetch : enable

頂点バッファとインデックスバッファを削除して、組み込み変数であるgl_HitTriangleVertexPositionsEXTから頂点位置を直接フェッチできるようになります。

- layout(buffer_reference, scalar) buffer VertexBuffer { vec3 vertexBuffer[]; };
- layout(buffer_reference, scalar) buffer IndexBuffer { uint indexBuffer[]; };

void main(){
-   uint triIndex0 = indexBuffer[firstIndex + gl_PrimitiveID*3 + 0];
-   uint triIndex1 = indexBuffer[firstIndex + gl_PrimitiveID*3 + 1];
-   uint triIndex2 = indexBuffer[firstIndex + gl_PrimitiveID*3 + 2];

-   vec3 vertPos0 = vertexBuffer[triIndex0];
-   vec3 vertPos1 = vertexBuffer[triIndex1];
-   vec3 vertPos2 = vertexBuffer[triIndex2];

+   vec3 vertPos0 = gl_HitTriangleVertexPositionsEXT[0];
+   vec3 vertPos1 = gl_HitTriangleVertexPositionsEXT[1];
+   vec3 vertPos2 = gl_HitTriangleVertexPositionsEXT[2];

    vec3 normal = cross(vertPos1 - vertPos0, vertPos2 - vertPos0);
    // ...
}

実際に使ってみたコード

実際に書いてみたリポジトリを置いておきます。

https://github.com/yknishidate/single-file-vulkan-pathtracing

参考文献

Vulkan-Docs/proposals/VK_KHR_ray_tracing_position_fetch.adoc

Vulkan-Docs/appendices/VK_KHR_ray_tracing_position_fetch.adoc

Introducing Vulkan Ray Tracing Position Fetch Extension - Khronos Blog

Discussion