当前位置:网站首页>【TA-霜狼_may-《百人计划》】图形3.7.2 command buffer简

【TA-霜狼_may-《百人计划》】图形3.7.2 command buffer简

2022-08-11 07:05:00 zczplus

3.7.2.1 Command buffer 简介

Command buffer: 用来存储渲染命令的缓冲区。
Command buffer保存着渲染命令列表,如(set render target,draw mesh等等),可以设置在摄像机渲染期间的不同点执行。

为什么会有command buffer

在这里插入图片描述
利用Command buffer帮助我们告诉管线进行什么样的绘制操作。

在OpenGL中,渲染过程中,出于渲染流程的需要,会频繁绑定VAO,VBO,FBO这类Buffer Object。这样重复性的操作即繁琐也缺乏可扩展性。

因此可以对一些重复性的操作进行提取封装:使用Shader类负责编译,在Model类添加一些读取模型,绑定VAO,VBO操作函数等等。

把渲染流程分为一个一个Pass进行编写,更加容易辨识在每个渲染流程中应该做什么,计算出什么结果。
在这里插入图片描述
出于跨平台的需要,unity对底层api进行进一步的处理,就得到了CommandBuffer。

Unity中Command Buffer的使用

回到Unity中,打开FrameDebugger,可以看到场景的渲染流程。对应ForwardRenderer.cs脚本中的

流程对应Pass
MainLightShadowCasterPassm_MainLightShadowCasterPass
DepthOnlyPassm_DepthPrepass
ColorGrandingLutPassm_ColorGradingLutPass
DrawObjectsPassm_RenderOpaqueForwardPass
DrawSkyboxPassm_DrawSkyboxPass
CopyColorPassm_CopyColorPass
PostProcessPassm_PostProcessPass
PostProcessPassm_FinalPostProcessPass

上表对应默认的URP管线
为了更好地扩展unity渲染管线,unity提供了CommandBuffer,让你根据自己的需求,在不同的渲染阶段插入绘制指令,例如:DrawRenderer,DrawMesh,DrawProcedure,绘制的时候也可以根据需要设置绘制时材质(Material)的MaterialPropertyBlock更改当前绘制的材质属性。
在这里插入图片描述
图中利用RenderFeature在BeforeRenderingOpaques的时候利用DrawMesh指令渲染了一个Box。
MaterialPropertyBlock比直接修改Material的优势是:不会创建出新的材质实例。

3.7.2.2 从自定义RenderPipeline分析ScriptableRenderContext 与 CommandBuffer

本节从最简单的自定义RenderPipeline开始分析如何构造一个Scriptable Render Pipeline。
然后再分析Pass的概念以及CommandBuffer和ScriptableRenderContext之间的关系。

RenderPipeline结构

在这里插入图片描述
首先先写一个继承自RenderPipeline的自定义管线类,类中有一个CameraRenderer对象,CameraRenderer朱啊哟负责的是渲染的主要逻辑。

继承自RenderPipeline的Render方法需要重写,可以看到这里的Cameras是一个数组,说明了当场景里有多个相机时,需要我们在这个RenderPipeline的Render函数中去遍历所有的Camera进行一个处理操作。

在Project中创建出RenderPipeline.Asset

在这里插入图片描述

为了创建一个Asset文件,只需要集成RenderPipelineAsset以及在类前面添加一个Attribute标签表示创建的资源在哪一个创建的列表的哪一个位置。

当然,这个继承RenderPipelineAsset也必须要实现CreatePipeline方法,并且返回一个RenderPipeline实例。

Renderer

最后就是负责主要渲染逻辑的Renderer类,直译过来就是渲染器,渲染器的Render方法的参数可以根据需求进行设置。可以看到在Render函数中朱啊哟的工作就是使用CommandBuffer把渲染过程相关指令写入到ScriptableRenderContext,最后ScriptalbeRenderContext使用Submit提交指令。为了方便组织渲染的流程和复用,可以把其中渲染的一段流程抽离出来单独写作一个Pass。
在这里插入图片描述

ScriptableRenderContext

在正式说Commandbuffer的作用之前,必须先清除ScriptableRenderContext在SRP中的作用。
ScriptableRenderContext: Defines state and drawing commands that custom render pipelines use.use a ScriptableRenderContext to schedule and submit state updates and drawing commands to the GPU.
指定自定义渲染管线渲染时的渲染状态和声明绘制指令,ScriptableRenderContext 负责调度和提交渲染状态的更新以及绘制指令到GPU。

说到渲染状态,在使用Opengl的时候,我们有时候也会根据渲染需要使用glEnable(xxxxx)更改渲染状态,使用BindVAO/VBO或者FBO/RBO这些命令,告诉GPU绘制的状态以及需要拿什么数据进行绘制,以及绘制到哪里。

渲染状态的更新(RenderStateBlock)

在这里插入图片描述
对于渲染状态的更新,体现最明显的是在context.DrawRenderers这个指令,可以看到DrawObjectPass在构造函数中它的RenderStateBlock是Nothing。

所以它对于Opaque pass也好,Transparent pass也好,它渲染状态的更新是跟每个Shader中各自的Depth、ZWrite、Blend等等的状态设置有关。
而下面的StencilState则是与在ForwardRenderer中的ForwardRendererData的具体设置有关。
在这里插入图片描述

context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref filterSettings, ref m_RenderStateBlock);

这个函数是最常见用于绘制一批物体,在SRP中,

  1. CullingResult是记录对物体,灯光,反射探针进行剔除的
  2. DrawingSetting设置绘制顺序以及绘制时使用哪一个Shader中的Pass
  3. FilteringSetting设置过滤设置渲染指定的Layer,
  4. RenderStateBlock更改(StateBlock)来重载深度、模板写入方式。

Command Buffers in Unity

Command Buffers 出现的目的是为了扩展Unity的渲染管线(Rendering Pipeline) ,一个Command Buffer 中存储很多绘制命令(Rendering Command),这些 Rendering Command 其实就是OpenGL或者DirectX 中的一些列指令,比如glDrawElement,glClear等。
Command Buffer 扩展渲染管线的方法是:预定义一系列的渲染指令,然后在特定的时机去执行这些指令。
这些特定的时机是由我们来自定义指定的,下图渲染过程中的绿点说明了这些可以指定的时机:
在这里插入图片描述
Skybox的渲染是在不透明图像效果之后,半透明物体之前。
因为不透明物体的绘制是从前往后,而半透明物体的绘制是从后往前的。Command buffers 可以用来代替 Image Effect ,也可以和Image Effect 一起使用。

官方毛玻璃案例分析:

效果如图:
在这里插入图片描述

原理分析:

  1. 在不透明物体和天空盒渲染完成之后,复制渲染图像到一个临时的RT(RenderTexture)上,然后对其进行模糊处理,将处理的结果应用到一个Shader全局参数上。
  2. 这么一来,所有在天空盒之后渲染的物体(例如所有的半透明物体)可以采样这个“模糊处理后的场景图像”。
    这种做法的效果类似 GrabPass ,但是比抓取屏幕的效率更高一些。

存在问题:

  1. 在Scene视图,目前并不能正确捕捉渲染结果,只能捕捉到天空盒。
  2. 在Android手机上测试,效果有些差别。在这里插入图片描述

代码实现

CommandBufferBlurRefraction.cs
在这里插入图片描述
用于渲染毛玻璃的Shader:GlassWithoutGrab.shader
在这里插入图片描述
用于模糊的Shader:SeparableBlur.shader
在这里插入图片描述

总结

  1. Command Buffer功能非常强大,它不仅可以用来处理Render Texture,也可以用于直接渲染物体:使用CommandBuffer.DrawMesh 和CommandBuffer.DrawRenderer 两个API 来实现。两者不同之处在于:DrawMesh 可以手动指定变换矩阵,更加灵活,同时也更加复杂。
  2. 使用Command Buffer 渲染物体时,如果给 shaderPass 形参传递了 -1 值,将会执行Shader中的所有Pass,但是需要注意:
if (!(LightMode == nullLightMode == ForwardBaseLightMode == ForwardAdd)){// Command Buffer 执行的渲染结果会出现问题~;}
  1. 执行Command Buffer 的方法:
    • 使用Camera.AddCommandBuffer()为摄像机指定的渲染事件添加CommandBuffer;
    • 也可以使用Graphics.ExecuteCommandBuffer()立即执行或Graphics.ExecuteCommandBufferAsync(); 异步执行 。
  2. 在使用Command Buffer的时候,一定要特别注意执行的时机和渲染的先后顺序,避免出现不可预估的渲染结果。Command Buffer的特点是可以在指定的时机执行一些特殊的渲染操作,从而达到节省资源和实现特殊效果的目的。Command Buffer 固然好用,切记,不可为了Command Buffer 而刻意使用Command Buffer,这样往往得不偿失

百人里面的太干了啃不动,后半部分FrameBuffer的介绍看的框架目录里面提供的另一篇简短的博客

作业

展开传送门效果

要点:

  • 传送门展开
  • 传送门模糊
  • 传送门与物体碰撞的描边
    在做了,在做了。o(╥﹏╥)o
原网站

版权声明
本文为[zczplus]所创,转载请带上原文链接,感谢
https://blog.csdn.net/weixin_42221907/article/details/126222215