Basic Ray Tracing
prepare
- VkPhysicalDeviceRayTracingPipelinePropertiesKHR
- 获取光追管线属性
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR
- VkPhysicalDeviceProperties2
- vkGetPhysicalDeviceProperties2
- VkPhysicalDeviceAccelerationStructureFeaturesKHR
- 获取加速属性
- VkPhysicalDeviceFeatures2
- vkGetPhysicalDeviceFeatures2
- 获取此示例所需的与光线跟踪和加速度结构相关的函数指针
- PFN_vkGetBufferDeviceAddressKHR
- PFN_vkCmdBuildAccelerationStructuresKHR
- PFN_vkBuildAccelerationStructuresKHR
- PFN_vkCreateAccelerationStructureKHR
- PFN_vkDestroyAccelerationStructureKHR
- PFN_vkGetAccelerationStructureBuildSizesKHR
- PFN_vkGetAccelerationStructureDeviceAddressKHR
- PFN_vkCmdTraceRaysKHR
- PFN_vkGetRayTracingShaderGroupHandlesKHR
- PFN_vkCreateRayTracingPipelinesKHR
- createBottomLevelAccelerationStructure: 在本地创建模型底层加速结构信息
- 创建包含场景实际几何体(顶点、三角形)的底层加速结构
- 创建一个三角形的VBO IBO
- createBuffer: VBO 这里没有使用staging buffer
- createBuffer: IBO
- createBuffer: Transform buffer
- 创建三个VkDeviceOrHostAddressConstKHR,分别存放三个buffer的指针(deviceAddress)
- vertexBufferDeviceAddress : getBufferDeviceAddress
- indexBufferDeviceAddress: getBufferDeviceAddress
- transformBufferDeviceAddress: getBufferDeviceAddress
- 创建加速结构
- VkAccelerationStructureGeometryKHR
- VkAccelerationStructureBuildGeometryInfoKHR: 几何信息
- VkAccelerationStructureBuildSizesInfoKHR:Get size info
- createAccelerationStructureBuffer: 创建加速结构buffer
- VkBufferCreateInfo:特殊的参数
- sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO
- usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR
- vkCreateBuffer: 下面使用的参数结构体都使用加速结构相关参数
- vkGetBufferMemoryRequirements
- vkAllocateMemory
- vkBindBufferMemory
- VkAccelerationStructureCreateInfoKHR
- vkCreateAccelerationStructureKHR: 创建加速结构
- 创建光追加速结构数据buffer
- RayTracingScratchBuffer = createScratchBuffer()
- 创建暂存缓冲区(ScratchBuffer)以保存线追加速结构数据
- RayTracingScratchBuffer:结构体
- VkBufferCreateInfo
- vkCreateBuffer
- vkGetBufferMemoryRequirements
- vkAllocateMemory
- vkBindBufferMemory
- VkBufferDeviceAddressInfoKHR:结构体
- vkGetBufferDeviceAddressKHR
- VkAccelerationStructureBuildGeometryInfoKHR
- VkAccelerationStructureBuildRangeInfoKHR
- accelerationStructureFeatures.accelerationStructureHostCommands
- 获取本机属性, 判断硬件是否支持加速结构创建
- 支持在Host中创建buffer
- vkBuildAccelerationStructuresKHR
- 不支持就在驱动(device)创建
- createCommandBuffer
- vkCmdBuildAccelerationStructuresKHR
- flushCommandBuffer
- VkAccelerationStructureDeviceAddressInfoKHR:结构体
- vkGetAccelerationStructureDeviceAddressKHR
- deleteScratchBuffer
- 删除 ScratchBuffer
- vkFreeMemory
- vkDestroyBuffer
- createTopLevelAccelerationStructure: 创建顶层加速结构信息(scene’s object instances)
- TopLevel和BottomLevel的区别, 个人认为 BottomLevel 创建每个面片的AABB的加速结构, 而TopLevel是根据模型AABB创建加速结构
- VkTransformMatrixKHR: 单位矩阵
- VkAccelerationStructureInstanceKHR
- Buffer for instance data
- VkDeviceOrHostAddressConstKHR
- getBufferDeviceAddress:从用于获取光追所需的缓冲区的设备地址
- VkBufferDeviceAddressInfoKHR
- vkGetBufferDeviceAddressKHR
- VkAccelerationStructureGeometryKHR
- geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR
- VkAccelerationStructureBuildGeometryInfoKHR:结构体
- VkAccelerationStructureBuildSizesInfoKHR: 结构体
- vkGetAccelerationStructureBuildSizesKHR
- createAccelerationStructureBuffer
- VkAccelerationStructureCreateInfoKHR
- RayTracingScratchBuffer = createScratchBuffer(): BottomLevel 中使用同样方法
- VkAccelerationStructureBuildGeometryInfoKHR
- VkAccelerationStructureBuildRangeInfoKHR
- accelerationStructureFeatures.accelerationStructureHostCommands
- true: vkBuildAccelerationStructuresKHR
- false:
- createCommandBuffer
- vkCmdBuildAccelerationStructuresKHR
- flushCommandBuffer
- VkAccelerationStructureDeviceAddressInfoKHR:结构体
- deleteScratchBuffer
- instancesBuffer.destroy()
- createStorageImage(): 存放光追渲染结果:
- VkImageCreateInfo image = vks::initializers::imageCreateInfo();
- vkCreateImage
- vkGetImageMemoryRequirements
- vkAllocateMemory
- vkBindImageMemory
- VkImageViewCreateInfo
- vkCreateImageView
- createCommandBuffer
- setImageLayout
- flushCommandBuffer - createUniformBuffer
- createBuffer
- updateUniformBuffers
- createRayTracingPipeline
- VkDescriptorSetLayoutBinding:结构体
- VkDescriptorSetLayoutCreateInfo:结构体
- vkCreateDescriptorSetLayout
- VkPipelineLayoutCreateInfo
- vkCreatePipelineLayout
- Setup ray tracing shader groups
- VkPipelineShaderStageCreateInfo
- Ray generation group
- VkRayTracingShaderGroupCreateInfoKHR: 结构体,存放shader和其他配置信息
- Miss group: 光追未命中
- VkRayTracingShaderGroupCreateInfoKHR
- shader: miss.rmiss.spv
- Closest hit group: 光追命中
- VkRayTracingShaderGroupCreateInfoKHR
- shader: closesthit.rchit.spv
- Create the ray tracing pipeline
- VkRayTracingPipelineCreateInfoKHR:结构体
- vkCreateRayTracingPipelinesKHR
- createShaderBindingTable
- 创建用于加速结构的 shader 绑定表(Shader Binding Tables)-(SBT)
- vkGetRayTracingShaderGroupHandlesKHR
- createBuffer: 创建SBT – raygen
- 使用字段VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR
- createBuffer: miss
- createBuffer: hit
- memcpy
- memcpy
- memcpy
- createDescriptorSets
- vkCreateDescriptorPool
- vkAllocateDescriptorSets
- writeDescriptorSet
- writeDescriptorSet
- vkUpdateDescriptorSets
- buildCommandBuffers
- handleResize
- vkDestroyImageView
- vkDestroyImage
- vkFreeMemory
- createStorageImage:之前有用到该方法
- vkBeginCommandBuffer
- 在着色器绑定表中设置指向着色器的缓冲区
- VkStridedDeviceAddressRegionKHR: raygen SBT
- VkStridedDeviceAddressRegionKHR: miss SBT
- VkStridedDeviceAddressRegionKHR: hit SBT
- vkCmdBindPipeline
- VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR
- vkCmdBindDescriptorSets
- vkCmdTraceRaysKHR
- Copy ray tracing output to swap chain image
- Prepare ray tracing output image as transfer source
- vkCmdCopyImage
- setImageLayout
- setImageLayout
- vkEndCommandBuffer
render
- draw
- prepareFrame
- vkQueueSubmit
- submitFrame
- updateUniformBuffers
shader
-
raygen.rgen:计算与顶层加速结构碰撞的点
- #extension GL_EXT_ray_tracing : enable
//需要绑定topLevel的加速结构
layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS;
layout(binding = 1, set = 0, rgba8) uniform image2D image;
layout(binding = 2, set = 0) uniform CameraProperties
- layout(location = 0) rayPayloadEXT vec3 hitValue;
void main()
{
//获取像素中心像素值
const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + vec2(0.5);
//获取获取中心像素对于的uv值
const vec2 inUV = pixelCenter/vec2(gl_LaunchSizeEXT.xy);
vec2 d = inUV * 2.0 - 1.0;
//获取射线的原点,和出射方向
vec4 origin = cam.viewInverse * vec4(0,0,0,1);
vec4 target = cam.projInverse * vec4(d.x, d.y, 1, 1) ;
vec4 direction = cam.viewInverse*vec4(normalize(target.xyz), 0) ;
//设置射线t的值范围
float tmin = 0.001;
float tmax = 10000.0;
hitValue = vec3(0.0);
//根据topLevel加速结构和射线获取与加速结构碰撞的点坐标
//猜测traceRayEXT的结果存储在rayPayloadEXT中
traceRayEXT(topLevelAS, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, origin.xyz, tmin, direction.xyz, tmax, 0);
//将所有光线命中的点存储在图片中
imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(hitValue, 0.0));
}
-
miss.rmiss:
#version 460
#extension GL_EXT_ray_tracing : enable
//没太看明白, 应该是,如果射线与加速结构不相交,给一个默认值
layout(location = 0) rayPayloadInEXT vec3 hitValue;
void main()
{
hitValue = vec3(0.0, 0.0, 0.2);
}
-
closesthit.rchit
#version 460
#extension GL_EXT_ray_tracing : enable
#extension GL_EXT_nonuniform_qualifier : enable
//如果命中输出局部重心坐标的值
layout(location = 0) rayPayloadInEXT vec3 hitValue;
//命中点的局部重心坐标信息
hitAttributeEXT vec3 attribs;
void main()
{
const vec3 barycentricCoords = vec3(1.0f - attribs.x - attribs.y, attribs.x, attribs.y);
hitValue = barycentricCoords;
}
小结
这节主要将vulkan光追加速结构的设置方法,以及如何使用shader计算hit点。感觉封装的有点严重。但是大概能理解实现原理。从shader中只能看出,这里只是输出从渲染图像中,从每个像素发射射线所命中模型面片位置的局部中心坐标信息。至于如何渲染出最终结果这里还看不出来。估计这里只是把局部重心坐标的值作为颜色输出了(确定了, 就是这样子。 在miss阶段给了z的值为0.2,正是渲染结果的背景色)。
Ray Traced Shadows
prepare
- createBottomLevelAccelerationStructure: 在本地创建模型底层加速结构信息
- loadFromFile:加载模型
- 创建两个VkDeviceOrHostAddressConstKHR,分别存放vbo和ibo的指针(deviceAddress)
- vertexBufferDeviceAddress : getBufferDeviceAddress
- indexBufferDeviceAddress: getBufferDeviceAddress
- 创建加速结构
- VkAccelerationStructureGeometryKHR
- VkAccelerationStructureBuildGeometryInfoKHR: 几何信息
- VkAccelerationStructureBuildSizesInfoKHR:Get size info
- vkGetAccelerationStructureBuildSizesKHR
- createAccelerationStructure: 创建加速结构buffer
- VkBufferCreateInfo:特殊的参数
- sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO
- usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR
- vkCreateBuffer: 下面使用的参数结构体都使用加速结构相关参数
- vkGetBufferMemoryRequirements
- vkAllocateMemory
- vkBindBufferMemory
- VkAccelerationStructureCreateInfoKHR
- vkCreateAccelerationStructureKHR: 创建加速结构
- vkGetAccelerationStructureDeviceAddressKHR: AS device address
- createScratchBuffer
- 在构建底层加速结构的过程中创建一个小的scratch缓冲区
- VkAccelerationStructureBuildGeometryInfoKHR:
- VkAccelerationStructureBuildRangeInfoKHR
- accelerationStructureFeatures.accelerationStructureHostCommands
- 是
- vkBuildAccelerationStructuresKHR
- 否
- createCommandBuffer
- vkCmdBuildAccelerationStructuresKHR
- flushCommandBuffer
- deleteScratchBuffer
- createTopLevelAccelerationStructure
- 创建 top level 加速结构
- VkAccelerationStructureInstanceKHR
- createBuffer: for instance data
- VkDeviceOrHostAddressConstKHR
- getBufferDeviceAddress
- VkAccelerationStructureGeometryKHR
- VkAccelerationStructureBuildGeometryInfoKHR
- VkAccelerationStructureBuildSizesInfoKHR
- vkGetAccelerationStructureBuildSizesKHR
- createAccelerationStructure()
- createScratchBuffer ()
- VkAccelerationStructureBuildGeometryInfoKHR
- VkAccelerationStructureBuildGeometryInfoKHR
- VkAccelerationStructureBuildRangeInfoKHR
- accelerationStructureFeatures.accelerationStructureHostCommands
- 是
- vkBuildAccelerationStructuresKHR
- 否
- createCommandBuffer
- vkCmdBuildAccelerationStructuresKHR
- flushCommandBuffer
- deleteScratchBuffer
- instancesBuffer.destroy()
- createStorageImage(): 存放光追渲染结果:
- VkImageCreateInfo image = vks::initializers::imageCreateInfo();
- vkCreateImage
- vkGetImageMemoryRequirements
- vkAllocateMemory
- vkBindImageMemory
- VkImageViewCreateInfo
- vkCreateImageView
- createCommandBuffer
- setImageLayout
- flushCommandBuffer - createUniformBuffer
- createBuffer
- updateUniformBuffers
- createRayTracingPipeline
- VkDescriptorSetLayoutBinding:结构体
- VkDescriptorSetLayoutCreateInfo:结构体
- vkCreateDescriptorSetLayout
- VkPipelineLayoutCreateInfo
- vkCreatePipelineLayout
- Setup ray tracing shader groups
- VkPipelineShaderStageCreateInfo
- Ray generation group
- VkRayTracingShaderGroupCreateInfoKHR: 结构体,存放shader和其他配置信息
- Miss group: 光追未命中
- VkRayTracingShaderGroupCreateInfoKHR
- shader: miss.rmiss.spv
- shader: Second shader for shadows
- Closest hit group: 光追命中
- VkRayTracingShaderGroupCreateInfoKHR
- shader: closesthit.rchit.spv
- Create the ray tracing pipeline
- VkRayTracingPipelineCreateInfoKHR:结构体
- vkCreateRayTracingPipelinesKHR
- createShaderBindingTable
- 创建用于加速结构的 shader 绑定表(Shader Binding Tables)-(SBT)
- vkGetRayTracingShaderGroupHandlesKHR
- createShaderBindingTable:创建三个SBT
- createBuffer: 创建SBT – raygen
- 使用字段VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR
- createBuffer: miss
- createBuffer: hit
- memcpy
- memcpy
- memcpy
- createDescriptorSets
- vkCreateDescriptorPool
- vkAllocateDescriptorSets
- writeDescriptorSet: Ray tracing result image
- writeDescriptorSet: Uniform data
- writeDescriptorSet: Scene vertex buffer
- writeDescriptorSet: Scene index buffer
- vkUpdateDescriptorSets
- buildCommandBuffers
- handleResize
- createStorageImage
- storageImageDescriptor
- writeDescriptorSet
- vkBeginCommandBuffer
- vkCmdBindPipeline
- vkCmdBindDescriptorSets
- vkCmdTraceRaysKHR
- Copy ray tracing output to swap chain image
- setImageLayout
- setImageLayout
- vkCmdCopyImage
- setImageLayout
- setImageLayout
- vkEndCommandBuffer
render
- draw
- prepareFrame
- vkQueueSubmit
- submitFrame
- updateUniformBuffers
shader
-
raygen.rgen:计算与顶层加速结构碰撞的点
- #extension GL_EXT_ray_tracing : enable
//需要绑定topLevel的加速结构
layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS;
layout(binding = 1, set = 0, rgba8) uniform image2D image;
layout(binding = 2, set = 0) uniform CameraProperties
- layout(location = 0) rayPayloadEXT vec3 hitValue;
void main()
{
//获取像素中心像素值
const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + vec2(0.5);
//获取获取中心像素对于的uv值
const vec2 inUV = pixelCenter/vec2(gl_LaunchSizeEXT.xy);
vec2 d = inUV * 2.0 - 1.0;
//获取射线的原点,和出射方向
vec4 origin = cam.viewInverse * vec4(0,0,0,1);
vec4 target = cam.projInverse * vec4(d.x, d.y, 1, 1) ;
vec4 direction = cam.viewInverse*vec4(normalize(target.xyz), 0) ;
//设置射线t的值范围
float tmin = 0.001;
float tmax = 10000.0;
hitValue = vec3(0.0);
//根据topLevel加速结构和射线获取与加速结构碰撞的点坐标
//猜测traceRayEXT的结果存储在rayPayloadEXT中
traceRayEXT(topLevelAS, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, origin.xyz, tmin, direction.xyz, tmax, 0);
//将所有光线命中的点存储在图片中
imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(hitValue, 0.0));
}
-
miss.rmiss:
#version 460
#extension GL_EXT_ray_tracing : enable
layout(location = 0) rayPayloadInEXT vec3 hitValue;
void main()
{
hitValue = vec3(0.0, 0.0, 0.2);
}
-
shadow.rmiss:
#version 460
#extension GL_EXT_ray_tracing : require
layout(location = 2) rayPayloadInEXT bool shadowed;
void main()
{
shadowed = false;
}
#version 460
#extension GL_EXT_ray_tracing : require
#extension GL_EXT_nonuniform_qualifier : enable
layout(location = 0) rayPayloadInEXT vec3 hitValue;
layout(location = 2) rayPayloadEXT bool shadowed;
hitAttributeEXT vec3 attribs;
layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS;
layout(binding = 2, set = 0) uniform UBO
{
mat4 viewInverse;
mat4 projInverse;
vec4 lightPos;
int vertexSize;
} ubo;
layout(binding = 3, set = 0) buffer Vertices { vec4 v[]; } vertices;
layout(binding = 4, set = 0) buffer Indices { uint i[]; } indices;
struct Vertex
{
vec3 pos;
vec3 normal;
vec2 uv;
vec4 color;
vec4 _pad0;
vec4 _pad1;
};
Vertex unpack(uint index)
{
// Unpack the vertices from the SSBO using the glTF vertex structure
// The multiplier is the size of the vertex divided by four float components (=16 bytes)
const int m = ubo.vertexSize / 16;
vec4 d0 = vertices.v[m * index + 0];
vec4 d1 = vertices.v[m * index + 1];
vec4 d2 = vertices.v[m * index + 2];
Vertex v;
v.pos = d0.xyz;
v.normal = vec3(d0.w, d1.x, d1.y);
v.color = vec4(d2.x, d2.y, d2.z, 1.0);
return v;
}
void main()
{
//获取当前模型面片索引
ivec3 index = ivec3(indices.i[3 * gl_PrimitiveID], indices.i[3 * gl_PrimitiveID + 1], indices.i[3 * gl_PrimitiveID + 2]);
//获取模型顶点的所有信息
Vertex v0 = unpack(index.x);
Vertex v1 = unpack(index.y);
Vertex v2 = unpack(index.z);
// Interpolate normal
//计算hit点的重心坐标
const vec3 barycentricCoords = vec3(1.0f - attribs.x - attribs.y, attribs.x, attribs.y);
//根据重心坐标计算hit处的法线
vec3 normal = normalize(v0.normal * barycentricCoords.x + v1.normal * barycentricCoords.y + v2.normal * barycentricCoords.z);
// Basic lighting
vec3 lightVector = normalize(ubo.lightPos.xyz);
float dot_product = max(dot(lightVector, normal), 0.2);
//获取hit处的base color
hitValue = v0.color.rgb * dot_product;
// Shadow casting
float tmin = 0.001;
float tmax = 10000.0;
//获取hit顶点数据: 射线原点 + 时间*方向
vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT;
shadowed = true;
//再次使用traceRayEXT方法计算是否有阴影
// gl_RayFlagsTerminateOnFirstHitEXT , 第一次命中的点
// gl_RayFlagsOpaqueEXT : 是否有透明材质
// gl_RayFlagsSkipClosestHitShaderEXT: 跳过已命中的点
// lightVector: 是否有阴影射线方向是光源的方向
// Trace shadow ray and offset indices to match shadow hit/miss shader group indices
traceRayEXT(topLevelAS, gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsOpaqueEXT | gl_RayFlagsSkipClosestHitShaderEXT, 0xFF, 1, 0, 1, origin, tmin, lightVector, tmax, 2);
if (shadowed) {
hitValue *= 0.3;
}
}
小结
这节主要将vulkan光追阴影处理的方式, 感觉计算阴影的方法比较暴力, 直接在hit出发射出一条指向光源的光线, 如果命中就是存在阴影. 总体来看, vulkan 封装了光追的方法, 实现光追只需使用好这三个shader即可.