光线追踪
一组五个相互关联的扩展在 Vulkan API 中提供光线追踪支持。
其他 SPIR-V 和 GLSL 扩展也公开了着色器所需的必要可编程功能
许多光线追踪应用程序需要大型连续内存分配。由于地址空间的大小有限,这在 32 位系统上可能具有挑战性。虽然实现可以在 32 位系统上自由公开光线追踪扩展,但应用程序可能会遇到间歇性的内存相关问题,例如由于碎片化导致的分配失败。此外,某些实现可能会选择不在 32 位驱动程序上公开光线追踪扩展。 |
VK_KHR_acceleration_structure
加速结构是几何对象的依赖于实现的透明表示,用于光线追踪。通过将对象构建到加速结构中,可以针对已知的数据布局以高效的方式执行光线追踪。VK_KHR_acceleration_structure
扩展引入了构建和复制加速结构的功能,以及支持与内存序列化的功能。
光线管线(VK_KHR_ray_tracing_pipeline
)和光线查询(VK_KHR_ray_query
)都需要加速结构。
要创建加速结构
-
使用加速结构类型、几何类型、计数和最大大小填充
VkAccelerationStructureBuildGeometryInfoKHR
的实例。此时不需要填充几何数据。 -
调用
vkGetAccelerationStructureBuildSizesKHR
以获取执行构建所需的内存大小要求。 -
分配足够大小的缓冲区以保存加速结构(
VkAccelerationStructureBuildSizesKHR::accelerationStructureSize
)和构建暂存缓冲区(VkAccelerationStructureBuildSizesKHR::buildScratchSize
) -
调用
vkCreateAccelerationStructureKHR
以在缓冲区内的指定位置创建加速结构 -
调用
vkCmdBuildAccelerationStructuresKHR
以构建加速结构。先前填充的VkAccelerationStructureBuildGeometryInfoKHR
应在此处用作参数,以及目标加速结构对象、构建暂存缓冲区和几何数据指针(用于顶点、索引和变换)
VK_KHR_ray_tracing_pipeline
VK_KHR_ray_tracing_pipeline
扩展引入了光线追踪管线。这种新的渲染管线形式独立于传统的栅格化管线。光线追踪管线使用一组专用的着色器阶段,不同于传统的顶点/几何/片段阶段。光线追踪管线还使用专用命令来提交渲染工作(vkCmdTraceRaysKHR
和 vkCmdTraceRaysIndirectKHR
)。这些命令可以被视为与传统栅格化管线中的绘制命令(vkCmdDraw
和 vkCmdDrawIndirect
)有些类似。
要跟踪光线
-
使用
vkCmdBindPipeline
和VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR
绑定光线追踪管线 -
调用
vkCmdTraceRaysKHR
或vkCmdTraceRaysIndirectKHR
光线追踪管线引入了几个新的着色器域。这些如下所述

-
光线生成着色器表示光线追踪的起点。光线追踪命令(
vkCmdTraceRaysKHR
和vkCmdTraceRaysIndirectKHR
)启动一个着色器调用网格,类似于计算着色器。光线生成着色器构造光线,并通过调用 traceRayEXT() 开始跟踪。此外,它还会处理命中组的结果。 -
最近命中着色器在光线与最近的几何体相交时执行。应用程序可以支持任意数量的最近命中着色器。它们通常用于执行照明计算,并且可以递归地跟踪其他光线。
-
当光线在遍历期间未与任何几何体相交时,将执行未命中着色器,而不是最近命中着色器。未命中着色器的常见用途是采样环境贴图。
-
内置的相交测试是光线-三角形测试。相交着色器允许自定义相交处理。
-
类似于最近命中着色器,任何命中着色器在报告相交后执行。不同之处在于,任何命中着色器都会针对由 [tmin, tmax] 定义的射线区间内的任何相交调用,而不是针对射线原点最近的相交调用。任何命中着色器用于过滤相交,因此通常用于实现 alpha 测试。
VK_KHR_ray_query
VK_KHR_ray_query
扩展提供了从所有着色器类型(包括图形、计算和光线追踪管线)追踪光线的支持。
光线查询要求光线遍历代码显式包含在着色器中。这与光线追踪管线不同,在光线追踪管线中,光线生成、相交测试和光线-几何体命中处理表示为单独的着色器阶段。因此,尽管光线查询允许从更广泛的着色器阶段追踪光线,但它也限制了 Vulkan 实现可能应用于光线调度和追踪的优化范围。
该扩展不引入额外的 API 入口点。它只是为相关的 SPIR-V 和 GLSL 扩展(SPV_KHR_ray_query
和 GLSL_EXT_ray_query
)提供 API 支持。
VK_KHR_ray_query
提供的功能是对 VK_KHR_ray_tracing_pipeline
提供的功能的补充,这两个扩展可以一起使用。
rayQueryEXT rq;
rayQueryInitializeEXT(rq, accStruct, gl_RayFlagsTerminateOnFirstHitEXT, cullMask, origin, tMin, direction, tMax);
// Traverse the acceleration structure and store information about the first intersection (if any)
rayQueryProceedEXT(rq);
if (rayQueryGetIntersectionTypeEXT(rq, true) == gl_RayQueryCommittedIntersectionNoneEXT) {
// Not in shadow
}
VK_KHR_pipeline_library
VK_KHR_pipeline_library
引入了管线库。管线库是一个特殊的管线,它是使用 VK_PIPELINE_CREATE_LIBRARY_BIT_KHR
创建的,不能直接绑定和使用。相反,这些管线表示着色器、着色器组和相关状态的集合,可以链接到其他管线中。
VK_KHR_pipeline_library
不直接引入任何新的 API 函数,也不定义如何创建管线库。相反,此功能留给其他利用 VK_KHR_pipeline_library
提供的功能的扩展。目前,唯一的例子是 VK_KHR_ray_tracing_pipeline
。VK_KHR_pipeline_library
被定义为一个单独的扩展,以便将来在其他扩展中使用相同的功能,而无需引入对光线追踪扩展的依赖。
要创建光线追踪管线库
-
在调用
vkCreateRayTracingPipelinesKHR
时,在VkRayTracingPipelineCreateInfoKHR::flags
中设置VK_PIPELINE_CREATE_LIBRARY_BIT_KHR
要将光线追踪管线库链接到完整的管线中
-
将
VkRayTracingPipelineCreateInfoKHR::pLibraryInfo
设置为指向VkPipelineLibraryCreateInfoKHR
的实例 -
使用要用作链接输入的管线库填充
VkPipelineLibraryCreateInfoKHR::pLibraries
,并将VkPipelineLibraryCreateInfoKHR::libraryCount
设置为适当的值
VK_KHR_deferred_host_operations
VK_KHR_deferred_host_operations
引入了一种机制,用于跨多个线程分发昂贵的 CPU 任务。VK_KHR_deferred_host_operations
的设计目的是允许应用程序创建和管理线程,而不是在 Vulkan 驱动程序中引入线程池。
与 VK_KHR_pipeline_library
一样,VK_KHR_deferred_host_operations
被定义为一个单独的扩展,以便将来在其他扩展中使用相同的功能,而无需引入对光线追踪扩展的依赖。
只有明确指出支持延迟的操作才能被延迟。目前,唯一支持延迟的操作是 vkCreateRayTracingPipelinesKHR
、vkBuildAccelerationStructuresKHR
、vkCopyAccelerationStructureKHR
、vkCopyMemoryToAccelerationStructureKHR
和 vkCopyAccelerationStructureToMemoryKHR
要请求延迟操作
-
通过调用
vkCreateDeferredOperationKHR
创建一个VkDeferredOperationKHR
对象 -
调用您希望延迟的操作,将
VkDeferredOperationKHR
作为参数传递。 -
检查上述操作返回的
VkResult
-
VK_OPERATION_DEFERRED_KHR
表示操作已成功延迟 -
VK_OPERATION_NOT_DEFERRED_KHR
表示操作已立即成功完成 -
任何错误值都表示发生了错误
-
要将线程加入延迟操作,并贡献 CPU 时间来推进操作
-
从您希望参与操作的每个线程调用
vkDeferredOperationJoinKHR
-
检查
vkDeferredOperationJoinKHR
返回的VkResult
-
VK_SUCCESS
表示操作已完成 -
VK_THREAD_DONE_KHR
表示没有更多工作要分配给调用线程,但其他线程可能仍然有一些额外的工作要完成。当前线程不应尝试通过再次调用vkDeferredOperationJoinKHR
重新加入 -
VK_THREAD_IDLE_KHR
表示暂时没有工作要分配给调用线程,但将来可能会有其他工作可用。当前线程可能会在调用线程上执行一些其他有用的工作,并且稍后再次调用vkDeferredOperationJoinKHR
重新加入可能会证明是有益的
-
在操作完成后(即 vkDeferredOperationJoinKHR
返回 VK_SUCCESS
),调用 vkGetDeferredOperationResultKHR
以获取操作的结果。
光线追踪的同步
-
对于着色器中的追踪或查询调用,请将
VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR
与加速结构的相应着色器阶段结合使用 -
对于光线追踪管线中着色器绑定表的访问,请将
VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR
与VK_ACCESS_SHADER_READ_BIT
或VK_ACCESS_2_SHADER_BINDING_TABLE_READ_BIT_KHR
结合使用 -
对于加速结构构建,请将
VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR
与与正在访问的资源对应的访问位结合使用-
目标 AS 使用
VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR
-
源 AS(例如,用于更新)使用
VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR
-
暂存缓冲区需要
VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR
和VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR
-
顶点/索引/实例/变换缓冲区使用
VK_ACCESS_SHADER_READ_BIT
-
-
对于加速结构复制命令,请使用
VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_COPY_BIT_KHR
或VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR
,同样,访问标志取决于源-
目标 AS 使用
VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR
-
源 AS 使用
VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR
-
目标缓冲区使用
VK_ACCESS_TRANSFER_WRITE_BIT
-
源缓冲区使用
VK_ACCESS_TRANSFER_READ_BIT
-
-
对于间接追踪调用,间接缓冲区是
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT
,具有VK_ACCESS_INDIRECT_COMMAND_READ_BIT
-
对于间接加速结构构建,间接缓冲区是
VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR
,具有VK_ACCESS_INDIRECT_COMMAND_READ_BIT
-
对于微映射构建,请将
VK_PIPELINE_STAGE_2_MICROMAP_BUILD_BIT_EXT
与与正在访问的资源对应的访问位结合使用-
目标微映射使用
VK_ACCESS_2_MICROMAP_WRITE_BIT_EXT
-
暂存缓冲区需要
VK_ACCESS_2_MICROMAP_WRITE_BIT_EXT
和VK_ACCESS_2_MICROMAP_READ_BIT_EXT
-
输入缓冲区使用
VK_ACCESS_SHADER_READ_BIT
-
-
对于微映射复制命令,请使用
VK_PIPELINE_STAGE_2_MICROMAP_BUILD_BIT_EXT
,同样,访问标志取决于源-
目标微映射使用
VK_ACCESS_2_MICROMAP_WRITE_BIT_EXT
-
源微映射使用
VK_ACCESS_2_MICROMAP_READ_BIT_EXT
-
目标缓冲区使用
VK_ACCESS_TRANSFER_WRITE_BIT
-
源缓冲区使用
VK_ACCESS_TRANSFER_READ_BIT
-
与其他复制操作不同, 使用 使用 |
光线追踪最佳实践
最大限度地减少并发活动的光线查询对象的数量
光线查询对象在线程私有存储方面可能很昂贵,因此为了提高性能,最好尽可能少使用。在大多数情况下,即使追踪多条光线,也应该可以使用单个光线查询对象,因为正在发出新光线的终止光线可以使用相同的对象。只有当多个遍历需要同时处于活动状态时,才需要在同一个着色器中使用多个光线查询,并且着色器的设计应最大限度地减少活动遍历的数量。