VK_KHR_ray_tracing_position_fetchの使い方
この記事はレイトレ合宿9アドベントカレンダーの記事です。前の記事はgamさんのObject Space Raymarching in Unreal Engine 5.2です!
VK_KHR_ray_tracing_position_fetch とは?
VK_KHR_ray_tracing_position_fetchは Vulkan 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);
// ...
}
実際に使ってみたコード
実際に書いてみたリポジトリを置いておきます。
参考文献
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