上一节了解了 Piccolo 中两种不同的渲染路径的具体实现,这一节我们使用 RenderDoc 帧调试工具来验证整个渲染流程。
1 回顾渲染路径
Piccolo 引擎默认的渲染路径是延迟渲染,因此我们再次回顾延迟渲染路径:
1 | void RenderPipeline::deferredRender(std::shared_ptr<RHI> rhi, std::shared_ptr<RenderResourceBase> render_resource) |
首先是平行光的 Shadow Pass,然后是点光源的 Shadow Pass,最后是相机的 Pass,其中相机的 Pass 又包含很多 Subpass,也就是 draw()
函数中的流程:
1 | void MainCameraPass::draw(ColorGradingPass& color_grading_pass, |
可以看到这些 Subpass 按照顺序依次是:
drawMeshGbuffer()
drawDeferredLighting()
drawBillboardParticle()
tone_mapping_pass.draw()
color_grading_pass.draw()
if (m_enable_fxaa) fxaa_pass.draw()
drawAxis()
ui_pass.draw()
combine_ui_pass.draw()
2 帧调试
常用的图形调试工具有 Intel GPA、Nvidia Nsight 和 RenderDoc。他们大概有以下一些特点:
- Intel GPA 简单易用,用于 PC 调试
- Nsight 功能强大复杂,用于 PC 调试
- RenderDoc 兼容性强,用于PC、移动设备、主机等
接下来我们使用 RenderDoc 来抓取引擎运行时的一帧并查看这一帧的渲染流程。
左侧 Event 列表即为当前帧的绘制流程。
我们知道 Vulkan 中进行渲染流程其实就是向 Command Buffer 中提交命令,Command Buffer 记录命令后最后统一提交给设备的 Queue 去执行,执行完毕后渲染就完成了,最后送显(Present)就将画面显示在了屏幕上。
因此每一帧的绘制都以 vkBeginCommandBuffer
开始,以vkEndCommandBuffer
结束,命令记录完之后调用 vkQueueSubmit
提交给设备执行,最后调用 vkQueuePresentKHR
送显。
接下来就是一系列的渲染指令,首先是 Colour Pass #1 为平行光阴影绘制,如下图绘制了平行光的 Shadow Map:
然后是 Colour Pass #2 点光源的 Shadow Map,但因为我们的场景目前还没有点光源,因此 Shadow Map 没有内容:
接下来 Colour Pass #3 对应主相机 Pass 中的drawMeshGbuffer()
,逐模型逐 Mesh 的绘制了 G-buffer:
右侧的 output 列表可以看到 G-Buffer 中有哪些内容,包括法线 Buffer、颜色 Buffer、深度 Buffer 等:
接下来按照代码流程切换到了下一个 Subpass,因此先发送了命令 vkCmdNextSubpass
,然后调用了 drawDeferredLighting()
进行延迟光照渲染:
接下来继续切换下一个 Subpass,进行粒子特效及参与介质的渲染 drawBillboardParticle()
,但该功目前还未实现,因此继续切换 Next Subpass 来到后处理的部分。
后处理首先进行了色调映射 tone_mapping_pass.draw()
得到了更加鲜明的结果:
然后是切换下一个 Subpass 来到 color_grading_pass.draw()
,但目前的 LUT 颜色映射没有对颜色进行变换,因此没有进行操作:
然后是 fxaa 抗锯齿,默认也没有开启,因此也没有进行操作,之后是绘制选中目标的坐标轴 drawAxis()
:
然后是绘制 UI 界面 ui_pass.draw()
:
最后是将 UI 界面和渲染的图像结合起来的 combine_ui_pass.draw()
:
这样就得到了我们引擎的一帧画面。
RenderDoc 还可以查看每个渲染命令绑定的 Pipeline,以及 Pipeline 绑定的资源 DescriptorSets 等:
还可以看到每个 Pass 的输入纹理,纹理可以是我们准备的资源,也可以是上一个 Pass 的渲染结果,比如 color grading pass 的输入是色调映射的渲染结果和 LUT 颜色查找表:
其他功能在之后用到的时候再继续深入探索。