目录
1. 初始化光线追踪扩展
首先,我们需要确保启用了必要的扩展和功能。
启用光线追踪扩展
std::vector<const char*> deviceExtensions = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME,
VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME,
VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME,
VK_KHR_SPIRV_1_4_EXTENSION_NAME,
VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME
};
检查扩展支持
bool checkDeviceExtensionSupport(VkPhysicalDevice device) {
uint32_t extensionCount;
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
std::vector<VkExtensionProperties> availableExtensions(extensionCount);
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());
std::set<std::string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());
for (const auto& extension : availableExtensions) {
requiredExtensions.erase(extension.extensionName);
}
return requiredExtensions.empty();
}
启用光线追踪功能
void enableRayTracingFeatures() {
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rayTracingPipelineFeatures{};
rayTracingPipelineFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR;
rayTracingPipelineFeatures.rayTracingPipeline = VK_TRUE;
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeatures{};
accelerationStructureFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR;
accelerationStructureFeatures.accelerationStructure = VK_TRUE;
VkPhysicalDeviceFeatures2 deviceFeatures2{};
deviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
deviceFeatures2.pNext = &rayTracingPipelineFeatures;
rayTracingPipelineFeatures.pNext = &accelerationStructureFeatures;
vkGetPhysicalDeviceFeatures2(physicalDevice, &deviceFeatures2);
}
2. 创建加速结构
加速结构用于加速光线追踪的碰撞检测。我们需要创建底层加速结构(BLAS)和顶层加速结构(TLAS)。
底层加速结构
VkAccelerationStructureKHR bottomLevelAS;
VkDeviceMemory bottomLevelASMemory;
void createBottomLevelAS() {
// Define geometry
VkAccelerationStructureGeometryKHR geometry{};
geometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR;
geometry.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
geometry.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
geometry.geometry.triangles.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR;
geometry.geometry.triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
geometry.geometry.triangles.vertexData.deviceAddress = getBufferDeviceAddress(vertexBuffer);
geometry.geometry.triangles.maxVertex = static_cast<uint32_t>(vertices.size());
geometry.geometry.triangles.vertexStride = sizeof(Vertex);
geometry.geometry.triangles.indexType = VK_INDEX_TYPE_UINT16;
geometry.geometry.triangles.indexData.deviceAddress = getBufferDeviceAddress(indexBuffer);
// Build information
VkAccelerationStructureBuildGeometryInfoKHR buildInfo{};
buildInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
buildInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
buildInfo.geometryCount = 1;
buildInfo.pGeometries = &geometry;
// Size information
VkAccelerationStructureBuildSizesInfoKHR sizeInfo{};
sizeInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR;
vkGetAccelerationStructureBuildSizesKHR(device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &buildInfo, maxPrimitiveCounts.data(), &sizeInfo);
// Create bottom level acceleration structure
VkAccelerationStructureCreateInfoKHR createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR;
createInfo.buffer = bottomLevelASBuffer;
createInfo.size = sizeInfo.accelerationStructureSize;
createInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
if (vkCreateAccelerationStructureKHR(device, &createInfo, nullptr, &bottomLevelAS) != VK_SUCCESS) {
throw std::runtime_error("failed to create bottom level acceleration structure!");
}
// Build command buffer
VkCommandBuffer commandBuffer = beginSingleTimeCommands();
VkAccelerationStructureBuildGeometryInfoKHR buildInfo{};
buildInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
buildInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
buildInfo.geometryCount = 1;
buildInfo.pGeometries = &geometry;
buildInfo.scratchData.deviceAddress = scratchBufferDeviceAddress;
buildInfo.dstAccelerationStructure = bottomLevelAS;
VkAccelerationStructureBuildRangeInfoKHR buildRangeInfo{};
buildRangeInfo.primitiveCount = static_cast<uint32_t>(indices.size()) / 3;
buildRangeInfo.primitiveOffset = 0;
buildRangeInfo.firstVertex = 0;
buildRangeInfo.transformOffset = 0;
std::vector<const VkAccelerationStructureBuildRangeInfoKHR*> buildRangeInfos = { &buildRangeInfo };
vkCmdBuildAccelerationStructuresKHR(commandBuffer, 1, &buildInfo, buildRangeInfos.data());
endSingleTimeCommands(commandBuffer);
// Free scratch buffer
vkDestroyBuffer(device, scratchBuffer, nullptr);
vkFreeMemory(device, scratchBufferMemory, nullptr);
}
- VkAccelerationStructureGeometryKHR 结构体定义加速结构的几何信息。
- VkAccelerationStructureBuildGeometryInfoKHR 结构体包含加速结构的构建信息。
- VkAccelerationStructureBuildSizesInfoKHR 结构体包含加速结构的大小信息。
- vkCreateAccelerationStructureKHR 函数创建加速结构。
- vkCmdBuildAccelerationStructuresKHR 函数在命令缓冲中记录加速结构的构建命令。
顶层加速结构
VkAccelerationStructureKHR topLevelAS;
VkDeviceMemory topLevelASMemory;
void createTopLevelAS() {
// Define instance
VkAccelerationStructureInstanceKHR instance{};
instance.transform = transformMatrix; // 4x3 transform matrix
instance.instanceCustomIndex = 0;
instance.mask = 0xFF;
instance.instanceShaderBindingTableRecordOffset = 0;
instance.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
instance.accelerationStructureReference = bottomLevelASAddress;
VkBuffer instanceBuffer;
VkDeviceMemory instanceBufferMemory;
createBuffer(sizeof(instance), VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, instanceBuffer, instanceBufferMemory);
void* data;
vkMapMemory(device, instanceBufferMemory, 0, sizeof(instance), 0, &data);
memcpy(data, &instance, sizeof(instance));
vkUnmapMemory(device, instanceBufferMemory);
VkAccelerationStructureGeometryKHR geometry{};
geometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR;
geometry.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR;
geometry.geometry.instances.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR;
geometry.geometry.instances.data.deviceAddress = getBufferDeviceAddress(instanceBuffer);
geometry.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
VkAccelerationStructureBuildGeometryInfoKHR buildInfo{};
buildInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR;
buildInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
buildInfo.geometryCount = 1;
buildInfo.pGeometries = &geometry;
buildInfo.srcAccelerationStructure = VK_NULL_HANDLE;
buildInfo.dstAccelerationStructure = topLevelAS;
buildInfo.scratchData.deviceAddress = scratchBufferDeviceAddress;
VkAccelerationStructureBuildSizesInfoKHR sizeInfo{};
sizeInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR;
vkGetAccelerationStructureBuildSizesKHR(device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &buildInfo, maxPrimitiveCounts.data(), &sizeInfo);
VkAccelerationStructureCreateInfoKHR createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR;
createInfo.buffer = topLevelASBuffer;
createInfo.size = sizeInfo.accelerationStructureSize;
createInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR;
if (vkCreateAccelerationStructureKHR(device, &createInfo, nullptr, &topLevelAS) != VK_SUCCESS) {
throw std::runtime_error("failed to create top level acceleration structure!");
}
VkCommandBuffer commandBuffer = beginSingleTimeCommands();
vkCmdBuildAccelerationStructuresKHR(commandBuffer, 1, &buildInfo, &buildRangeInfo);
endSingleTimeCommands(commandBuffer);
// Free scratch buffer
vkDestroyBuffer(device, scratchBuffer, nullptr);
vkFreeMemory(device, scratchBufferMemory, nullptr);
}
- VkAccelerationStructureInstanceKHR 结构体定义加速结构实例的信息。
- createBuffer 函数创建并分配缓冲,用于存储实例数据。
- VkAccelerationStructureGeometryKHR 结构体定义顶层加速结构的几何信息。
- VkAccelerationStructureBuildGeometryInfoKHR 结构体包含顶层加速结构的构建信息。
- vkCreateAccelerationStructureKHR 函数创建顶层加速结构。
- vkCmdBuildAccelerationStructuresKHR 函数在命令缓冲中记录加速结构的构建命令。
3. 创建光线追踪管线
光线追踪着色器
#version 460
#extension GL_EXT_ray_tracing : require
layout(set = 0, binding = 0) uniform accelerationStructureEXT topLevelAS;
layout(set = 0, binding = 1, rgba32f) uniform image2D resultImage;
layout(location = 0) rayPayloadEXT vec3 payload;
void main() {
vec3 origin = vec3(0.0, 0.0, -5.0);
vec3 direction = vec3(0.0, 0.0, 1.0);
uint rayFlags = gl_RayFlagsOpaqueEXT;
traceRayEXT(topLevelAS, rayFlags, 0xFF, 0, 1, 0, origin, 0.0, direction, 10000.0, 0);
imageStore(resultImage, ivec2(gl_LaunchIDEXT.xy), vec4(payload, 1.0));
}
编译光线追踪着色器:
glslc raygen_shader.glsl -o raygen_shader.spv
创建光线追踪管线
VkPipeline rayTracingPipeline;
VkPipelineLayout rayTracingPipelineLayout;
void createRayTracingPipeline() {
auto raygenShaderCode = readFile("raygen_shader.spv");
VkShaderModule raygenShaderModule = createShaderModule(raygenShaderCode);
VkPipelineShaderStageCreateInfo raygenShaderStageInfo{};
raygenShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
raygenShaderStageInfo.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR;
raygenShaderStageInfo.module = raygenShaderModule;
raygenShaderStageInfo.pName = "main";
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.setLayoutCount = 1;
pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout;
if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &rayTracingPipelineLayout) != VK_SUCCESS) {
throw std::runtime_error("failed to create ray tracing pipeline layout!");
}
VkRayTracingPipelineCreateInfoKHR pipelineInfo{};
pipelineInfo.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR;
pipelineInfo.stageCount = 1;
pipelineInfo.pStages = &raygenShaderStageInfo;
pipelineInfo.groupCount = 1;
pipelineInfo.pGroups = &raygenShaderGroup;
pipelineInfo.maxPipelineRayRecursionDepth = 1;
pipelineInfo.layout = rayTracingPipelineLayout;
if (vkCreateRayTracingPipelinesKHR(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &rayTracingPipeline) != VK_SUCCESS) {
throw std::runtime_error("failed to create ray tracing pipeline!");
}
vkDestroyShaderModule(device, raygenShaderModule, nullptr);
}
- VkPipelineShaderStageCreateInfo 结构体定义光线追踪着色器阶段的信息。
- VkPipelineLayoutCreateInfo 结构体包含创建管线布局的信息。
- VkRayTracingPipelineCreateInfoKHR 结构体包含创建光线追踪管线的信息。
- vkCreateRayTracingPipelinesKHR 函数创建光线追踪管线。
4. 执行光线追踪
记录光线追踪命令缓冲
VkCommandBuffer rayTracingCommandBuffer;
void recordRayTracingCommandBuffer() {
VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
if (vkBeginCommandBuffer(rayTracingCommandBuffer, &beginInfo) != VK_SUCCESS) {
throw std::runtime_error("failed to begin recording ray tracing command buffer!");
}
vkCmdBindPipeline(rayTracingCommandBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, rayTracingPipeline);
vkCmdBindDescriptorSets(rayTracingCommandBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, rayTracingPipelineLayout, 0, 1, &descriptorSet, 0, nullptr);
VkStridedDeviceAddressRegionKHR raygenShaderSbtEntry{};
raygenShaderSbtEntry.deviceAddress = getShaderBindingTableAddress(raygenSbtBuffer);
raygenShaderSbtEntry.stride = shaderGroupHandleSize;
raygenShaderSbtEntry.size = shaderGroupHandleSize;
vkCmdTraceRaysKHR(rayTracingCommandBuffer, &raygenShaderSbtEntry, &missShaderSbtEntry, &hitShaderSbtEntry, &callableShaderSbtEntry, WIDTH, HEIGHT, 1);
if (vkEndCommandBuffer(rayTracingCommandBuffer) != VK_SUCCESS) {
throw std::runtime_error("failed to record ray tracing command buffer!");
}
}
- vkCmdBindPipeline 函数绑定光线追踪管线。
- vkCmdBindDescriptorSets 函数绑定描述符集。
- VkStridedDeviceAddressRegionKHR 结构体定义着色器绑定表的地址和大小信息。
- vkCmdTraceRaysKHR 函数执行光线追踪。
提交光线追踪命令缓冲
void submitRayTracingCommandBuffer() {
VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &rayTracingCommandBuffer;
if (vkQueueSubmit(computeQueue, 1, &submitInfo, VK_NULL_HANDLE) != VK_SUCCESS) {
throw std::runtime_error("failed to submit ray tracing command buffer!");
}
vkQueueWaitIdle(computeQueue);
}
- VkSubmitInfo 结构体包含提交命令缓冲的信息。
- vkQueueSubmit 函数提交命令缓冲到计算队列。
- vkQueueWaitIdle 函数等待计算队列完成所有提交的命令缓冲。