Vulkan Samples 阅读 -- Compute Shader(二)N-body Simulation & Ray tracing

N-body Simulation

prepare

  • graphics.queueFamilyIndex
  • compute.queueFamilyIndex
    • 前两个的参数设置为了区别计算队列与图形队列
  • loadAssets:加载粒子使用的贴图
  • setupDescriptorPool
    • 这里多设置了一个池: VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
    • vkCreateDescriptorPool
  • prepareGraphics
    • prepareStorageBuffers
      • std::vector particleBuffer(numParticles);
        • 存放的粒子
      • createBuffer: 创建stagingBuffer用于存放粒子(STORAGE)
      • createBuffer: 注意这个buffer的创建使用的参数(计算管线的stagingbuffer, vs 的vbo)
      • createCommandBuffer
      • vkCmdCopyBuffer
      • graphics.queueFamilyIndex != compute.queueFamilyIndex
        • vkCmdPipelineBarrier: 如果现在管线是计算管线, 将vbo数据拷贝到计算管线
      • flushCommandBuffer
      • destroy
      • Binding description
        • 将绑定初始的粒子顶点所需描述符
    • prepareUniformBuffers: 主要是计算管线uniform
      • createBuffer
      • updateComputeUniformBuffers
      • updateGraphicsUniformBuffers
    • setupDescriptorSetLayout
      • vkCreateDescriptorSetLayout
      • vkCreatePipelineLayout
    • preparePipelines
      • vkCreateGraphicsPipelines
    • setupDescriptorSet
      • vkAllocateDescriptorSets
      • vkUpdateDescriptorSets
    • vkCreateSemaphore
  • prepareCompute
    • vkGetDeviceQueue
    • VkDescriptorSetLayoutBinding
      • descriptorSetLayoutBinding: Particle position storage buffer
      • descriptorSetLayoutBinding: Uniform buffer
    • vkCreateDescriptorSetLayout
    • vkCreatePipelineLayout
    • vkAllocateDescriptorSets
    • VkWriteDescriptorSet: 这里多了一个write描述符
      • writeDescriptorSet: Particle position storage buffer
      • writeDescriptorSet: Uniform buffer
    • vkUpdateDescriptorSets
    • vkCreateComputePipelines: particle_calculate, shader在此传入, 共两个pass
    • vkCreateComputePipelines: particle_integrate
    • vkCreateCommandPool
    • createCommandBuffer
    • vkCreateSemaphore
    • vkQueueSubmit
    • vkQueueWaitIdle
    • buildComputeCommandBuffer
      • vkBeginCommandBuffer
      • graphics.queueFamilyIndex != compute.queueFamilyIndex
        • vkCmdPipelineBarrier:将stagingbuffer写入的计算管线中
        • vkCmdBindPipeline
        • vkCmdBindDescriptorSets
        • vkCmdDispatch(PARTICLE_COUNT / 256) 一维工作组
      • vkCmdPipelineBarrier: 该barrier确保缓冲区写入已完成
      • vkCmdBindPipeline: 第二个pass
      • vkCmdDispatch
      • graphics.queueFamilyIndex != compute.queueFamilyIndex
        • 将计算管线数据写入到VS管线中
      • vkEndCommandBuffer
    • graphics.queueFamilyIndex != compute.queueFamilyIndex
      • vkCmdPipelineBarrier: 将vs数据Barrier到计算管线中
      • vkCmdPipelineBarrier: 将计算管线数据Barrier到VS管线中
    • flushCommandBuffer
  • buildCommandBuffers
    • loop
      • vkBeginCommandBuffer
      • graphics.queueFamilyIndex != compute.queueFamilyIndex
        • vkCmdPipelineBarrier: CS复制到VS中
      • vkCmdBeginRenderPass
      • vkCmdSetViewport
      • vkCmdSetScissor
      • vkCmdBindPipeline
      • vkCmdBindDescriptorSets
      • vkCmdPushConstants
      • vkCmdBindVertexBuffers
      • vkCmdDraw
      • drawUI
      • vkCmdEndRenderPass
      • graphics.queueFamilyIndex != compute.queueFamilyIndex
        • vkCmdPipelineBarrier: VS复制到CS中
      • vkEndCommandBuffer

render

  • draw
    • prepareFrame
    • vkQueueSubmit: Submit graphics commands
    • submitFrame
    • vkQueueSubmit:Submit compute commands
  • updateComputeUniformBuffers
  • updateGraphicsUniformBuffers

shader

  • CS1
    • 常量设置
      • layout (constant_id = 0) const int SHARED_DATA_SIZE = 512
      • 这个值不能超过显卡最大支持的size
    • 共享数据设置(共享应该只针对当前工作组)
      • shared vec4 sharedData[SHARED_DATA_SIZE]
      • 共享数据设置在vkCreateComputePipelines设置
        • specializationData.sharedDataSize
    • sharedData[gl_LocalInvocationID.x] = vec4(0.0): 共享数据直接读写即可
    • 获取共享数据结果需要等待所有计算单元完成对共享数据的操作, 因此需要使用同步信号
      • memoryBarrierShared();
      • barrier();
    for (int i = 0; i < ubo.particleCount; i += SHARED_DATA_SIZE)
    {
    	if (i + gl_LocalInvocationID.x < ubo.particleCount)
    	{
    		sharedData[gl_LocalInvocationID.x] = particles[i + gl_LocalInvocationID.x].pos;
    	}
    	else
    	{
    		sharedData[gl_LocalInvocationID.x] = vec4(0.0);
    	}
    
    	memoryBarrierShared();
    	barrier();
    	//遍历所有工作单元获取当前工作单元共享数据
    	for (int j = 0; j < gl_WorkGroupSize.x; j++)
    	{
    		vec4 other = sharedData[j];
    		vec3 len = other.xyz - position.xyz;
    		acceleration.xyz += GRAVITY * len * other.w / pow(dot(len, len) + SOFTEN, POWER);
    	}
    
    	memoryBarrierShared();
    	barrier();
    }
    
    
  • CS2
    • 做粒子运动计算
  • VS: 与上节相同
  • FS: 正常渲染即可

小结

   本节主要讲compute shader 共享数据的使用. 从代码上看,共享数据只针对当前工作组. 需要后续学习中确认.

Ray tracing

prepare

  • prepareStorageBuffers
    • std::vector spheres: 渲染使用的球
    • createBuffer: stagingBuffer
    • createBuffer: SSBO(cs的buffer, vs的VBO)
    • Copy to staging buffer
      • createCommandBuffer
      • vkCmdCopyBuffer
      • flushCommandBuffer
    • destroy
    • std::vector planes: 渲染使用的盒子
    • createBuffer: stagingBuffer
    • createBuffer: SSBO
      • createCommandBuffer
      • vkCmdCopyBuffer
      • flushCommandBuffer
    • destroy
  • prepareUniformBuffers
    • createBuffer: CS parameter
    • updateUniformBuffers
  • prepareTextureTarget: 准备一个纹理, 用于存放渲染结果
    • vkGetPhysicalDeviceFormatProperties
    • vkCreateImage
    • vkGetImageMemoryRequirements
    • vkAllocateMemory
    • vkBindImageMemory
    • createCommandBuffer
    • setImageLayout
    • flushCommandBuffer
    • vkCreateSampler
    • vkCreateImageView
  • setupDescriptorSetLayout
    • vkCreateDescriptorSetLayout: fs 读取GS结构sampler
    • vkCreatePipelineLayout:
  • preparePipelines
    • vkCreateGraphicsPipelines
  • setupDescriptorPool
    • 这里多设置了一个池: VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
    • 和 VK_DESCRIPTOR_TYPE_STORAGE_IMAGE
    • vkCreateDescriptorPool
  • setupDescriptorSet
    • vkAllocateDescriptorSets
    • vkUpdateDescriptorSets
  • prepareCompute
    • vkGetDeviceQueue
    • vkCreateDescriptorSetLayout
    • vkCreatePipelineLayout
    • vkAllocateDescriptorSets
    • vkUpdateDescriptorSets
    • Create compute shader pipelines
      • vkCreateComputePipelines
      • vkCreateCommandPool
      • vkAllocateCommandBuffers
      • vkCreateFence
      • buildComputeCommandBuffer
        • vkBeginCommandBuffer
        • vkCmdBindPipeline
        • vkCmdBindDescriptorSets
        • vkCmdDispatch
        • vkEndCommandBuffer
  • buildCommandBuffers
    • loop
      • vkBeginCommandBuffer
      • vkCmdPipelineBarrier
      • vkCmdBeginRenderPass
      • vkCmdSetViewport
      • vkCmdSetScissor
      • vkCmdBindDescriptorSets
      • vkCmdBindPipeline
      • vkCmdDraw
      • drawUI
      • vkCmdEndRenderPass
      • vkEndCommandBuffer

render

  • draw
    • prepareFrame
    • vkQueueSubmit: Submit graphics commands
    • submitFrame
    • vkWaitForFences
    • vkResetFences
    • vkQueueSubmit:Submit compute commands
  • updateUniformBuffers

shader

  • CS
    • 工作单元:
      • local_size_x = 16, local_size_y = 16
    • 结果使用texture
      • uniform writeonly image2D resultImage
    • 绑定渲染模型buffer
      • buffer Spheres: Sphere
      • buffer Planes: Planes
    • main
      • imageSize获取图像大小
      • 获取texture uv
        • vec2 uv = vec2(gl_GlobalInvocationID.xy) / dim: 当先像素坐标/宽高即: 0-1的uv值
      • rayO: 相机位置
      • rayD: 应该是以像素点为原点, 入射场景射线的方向
      • Basic color path
        • renderScene
          • #define MAXLEN 1000.0
          • float t = MAXLEN;
          • intersect(rayO, rayD, t)
            • loop spheres
              • sphereIntersect(rayO, rayD, spheres[i]): 判断当前射线是否与球相交
              • 获取与射线相交的模型id
              • 射线与球相交的交点(tSphere, 射线上交点相对t的参数(p = o + t*n))
            • loop planes: 与 loop spheres相同
            • 注意: 这里存在一个问题, 有可能一条射线同时和球与平面相交, 这里的选择是平面为最终相交模型
          • 获取相交顶点
          • 计算lv(lightPos - pos)
          • loop 平面 获取模型法线并计算该点的最终颜色(使用blinn phong模型)
          • loop 模型: 同样操作(感觉这个代码相当臃肿)
          • 计算阴影 calcShadow
            • loop spheres
              • 跳过当前相交的模型
              • sphereIntersect, 计算是否与射线相交
            • 如果相交即为阴影(即灯光和模型之间有模型遮挡)
            • color *= calcShadow(pos, lightVec, id, t)
          • reflectRay: 折射阶段
            • 计算下个一个射线的方向
          • rayO = pos: 更新相机位置为当前渲染的顶点
    • Reflection 折射阶段
      • loop RAYBOUNCES: 折射次数
        • renderScene 重复Basic color path
        • finalColor: 混合颜色
        • 更新reflectionStrength
    • imageStore 存储渲染结果
  • VS: 正常渲染即可
  • FS: 正常渲染即可

小结

   本节主要讲光追的基本方法, 感觉写的比较随意. 但是已经将光追诠释的相当清楚了. 个人理解, 这节的光追方法其实就是离线光追渲染方法. 只是这里没有去解渲染方程. 光追主要使用Computer Shader. 而VS和FS只是用来显示结果而已.

realesrgan-ncnn-vulkan-20211212-windows是一个基于ncnn框架和Vulkan图形API开发的图像超分辨率增强模型。它是由GitHub用户realsrgan开发的最新版本,最新发布日期为2021年12月12日,专为Windows操作系统而设计。 该模型的主要应用是图像超分辨率增强,通过提高图像的分辨率和细节,使图像看起来更加清晰和真实。它采用深度学习和卷积神经网络等先进的技术,能够将低分辨率的图像转换成高分辨率的图像,从而提升图像的质量和视觉效果。 realesrgan-ncnn-vulkan-20211212-windows的开发使用了ncnn框架和Vulkan图形API,这使得它能够在Windows系统上实现快速且高效的图像处理。ncnn是一个轻量级的深度学习框架,专注于在移动平台和嵌入式设备上实现高性能和低延迟的推理。而Vulkan图形API是一种跨平台的图形渲染和计算API,可以充分利用计算设备的性能,提供高效的图像处理和渲染能力。 realesrgan-ncnn-vulkan-20211212-windows的使用可以通过命令行或者图形界面进行,用户可以根据自己的需求和偏好选择适合的方式。该模型提供了训练好的权重参数,用户可以直接加载这些参数并进行图像超分辨率增强。此外,该模型还支持批量处理和视频处理,方便用户对多个图像进行处理。 总之,realesrgan-ncnn-vulkan-20211212-windows是一个高效、快速且易于使用的图像超分辨率增强模型,适用于Windows系统,并利用了ncnn框架和Vulkan图形API的优势,为用户提供了出色的图像处理效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值