当前位置: 首页 > 工具软件 > Four Shadows > 使用案例 >

Vulkan Samples 阅读 -- Hardware Accelerated Ray Tracing(一) Basic Ray Tracing &Ray Traced Shadows

益锦程
2023-12-01

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
        • 获取加速结构指针(address)
      • deleteScratchBuffer
        • 删除 ScratchBuffer
          • vkFreeMemory
          • vkDestroyBuffer
  • createTopLevelAccelerationStructure: 创建顶层加速结构信息(scene’s object instances)
    • TopLevel和BottomLevel的区别, 个人认为 BottomLevel 创建每个面片的AABB的加速结构, 而TopLevel是根据模型AABB创建加速结构
    • VkTransformMatrixKHR: 单位矩阵
    • VkAccelerationStructureInstanceKHR
    • Buffer for instance data
      • createBuffer
    • VkDeviceOrHostAddressConstKHR
    • getBufferDeviceAddress:从用于获取光追所需的缓冲区的设备地址
      • VkBufferDeviceAddressInfoKHR
      • vkGetBufferDeviceAddressKHR
    • VkAccelerationStructureGeometryKHR
      • geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR
        • 这里将加速结构的信息设置为instance
      • VkAccelerationStructureBuildGeometryInfoKHR:结构体
      • VkAccelerationStructureBuildSizesInfoKHR: 结构体
      • vkGetAccelerationStructureBuildSizesKHR
      • createAccelerationStructureBuffer
        • 创建加速结构buffer
      • 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和其他配置信息
          • shader: raygen.rgen.spv
      • 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:之前有用到该方法
        • vkUpdateDescriptorSets
    • vkBeginCommandBuffer
    • 在着色器绑定表中设置指向着色器的缓冲区
      • VkStridedDeviceAddressRegionKHR: raygen SBT
        • getBufferDeviceAddress
      • VkStridedDeviceAddressRegionKHR: miss SBT
        • getBufferDeviceAddress
      • VkStridedDeviceAddressRegionKHR: hit SBT
        • getBufferDeviceAddress
    • vkCmdBindPipeline
      • VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR
    • vkCmdBindDescriptorSets
    • vkCmdTraceRaysKHR
    • Copy ray tracing output to swap chain image
      • setImageLayout
    • Prepare ray tracing output image as transfer source
      • 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;
      • 射线Hit的坐标信息
    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和其他配置信息
          • shader: raygen.rgen.spv
      • 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;
      • 射线Hit的坐标信息
    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;
}
  • closesthit.rchit
#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即可.

 类似资料: