https://www.sohu.com/a/364110559_667928
https://zhuanlan.zhihu.com/p/98642798
不减少DC,由于编辑器的算法,会显示减少
优点:提前进行空间变化,减少运行时cpu的变换计算;且子模型之间共享材质,所以在多次DC调用之间并没有渲染状态的切换。
缺点:包体增大,运行时内存体积增大。
原理:在打包时对相同材质的静态物体进行的Vertex buffer和Index buffe进行提取,然后变换到世界空间下。在后续的绘制过程中,一次性提交整个合并模型的顶点数据,根据引擎的场景管理系统判断各个子模型的可见性。然后设置一次渲染状态,调用多次Draw call分别绘制每一个子模型。
标记为Static的静态物件(判断条件),在使用相同材质球的条件下,在Build(打包)的时候Unity会自动提取这些共享材质的静态模型的Vertex buffer和Index buffer(索引缓冲,给顶点索引,渲染的时候不用重复调用)。根据最终位置将模型的顶点数据变换到世界空间下,存进更大的Vertex buffer和Index buffer中。并记录每个子模型的并且记录每一个子模型的Index buffer数据在构建的大Index buffer中的起始及结束位置。
一次性提交整个合并模型的顶点数据,根据引擎的场景管理系统判断各个子模型的可见性。然后设置一次渲染状态,调用多次Draw call分别绘制每一个子模型。
优点:会降低DC数量
缺点:额外CPU性能消耗。所以对比一下性耗再做
原理:相当于减少CPU往GPU传递的时候的绘制命令(DC),以及GPU从VRAM里拿顶点数据的次数(一起拿)
在使用相同材质球的情况下,Unity会在运行时对于正在视野中的符合条件的动态对象在一个Draw call内绘制,所以会降低Draw Calls的数量。在进行场景绘制之前将所有的共享同一材质的模型的顶点信息变换到世界空间中,然后通过一次Draw call绘制多个模型,达到合批的目的。模型顶点变换的操作是由CPU完成的,所以这会带来一些CPU的性能消耗。并且计算的模型顶点数量不宜太多,否则CPU串行计算耗费的时间太长会造成场景渲染卡顿,所以Dynamic batching只能处理一些小模型。
对比:Dynamic batching相对于Static batching不需要预先复制模型顶点,所以在内存占用和发布的程序体积方面要优于Static batching。但是Dynamic batching会带来一些运行时CPU性能消耗,Static batching在这一点要比Dynamic batching更加高效。
打破:详见链接
可以接收多个光源的shader,在受到多个光源是无法合批
优点:GPU Instancing可以规避合并Mesh导致的内存与性能上升的问题,但是由于场景中所有符合该合批条件的渲染物体的信息每帧都要被重新创建,放入“统一/常量缓冲器”中
限制:碍于缓存区的大小限制,每一个CBuffer的大小要严格限制。
原理:在使用相同材质球、相同Mesh(预设体的实例会自动地使用相同的网格模型和材质)的情况下,Unity会在运行时对于正在视野中的符合要求的所有对象使用Constant Buffer将其位置、缩放、uv偏移、lightmapindex等相关信息保存在显存中的“统一/常量缓冲器”中,然后从中抽取一个对象作为实例送入渲染流程,当在执行DrawCall操作后,从显存中取出实例的部分共享信息与从GPU常量缓冲器中取出对应对象的相关信息一并传递到下一渲染阶段,与此同时,不同的着色器阶段可以从缓存区中直接获取到需要的常量,不用设置两次常量。
打破:详见链接
优点:与GPU Instancing相比,因为数据不再每帧被重新创建,而且需要保存进“统一/常量缓冲区”的数据排除了各自的位置、缩放、uv偏移、lightmapindex等相关信息,所以缓冲区内有更多的空间可以动态地存储场景中所有渲染物体的材质信息。由于数据不再每帧被重新创建,而是动态更新,所以SRP Batcher的本质并不会降低Draw Calls的数量,它只会降低Draw Calls之间的GPU设置成本。(相当于将多个dc一起提交到GPU)
(让每次batch(大的cbuffer)填满再上传)
(单一物体,例如只有草,insitance快,材质4+后batcher快)
原理:只要物体的Shader中变体一致,就可以启用SRP Batcher加速。它与上文GPU Instancing实现的原理相近,Unity会在运行时对于正在视野中的符合要求的所有对象使用“Per Object” GPU BUFFER(一个独立的Buffer) 将其位置、缩放、uv偏移、lightmapindex等相关信息保存在GPU内存中,同时也会将正在视野中的符合要求的所有对象使用CBuffer将材质信息保存在保存在显存中的“统一/常量缓冲器”中。
DX10后引入的常量缓冲区,允许着色器常量组合提交,而不是每次调用都传一次,降低着色器的传递的带宽。
基本原理:每一帧把可以进行批处理的模型网格进行合并,再把合并后的模型数据传递给GPU,然后使用同一个材质对其渲染。动态批处理的一个好处是实现方便,另一个好处是,经过批处理的物体仍然可以移动,这是由于在处理每帧时Unity都会重新合并一次网格。
条件限制:
Unity提供了另一种批处理方式,即静态批处理。相比于动态批处理来说,静态批处理适用于任何大小的几何模式。它的实现原理是,只在运行开始阶段,把需要进行静态批处理的模型合并到一个新的网络结构中,这意味着这些模型不可以在运行时刻被移动。但由于它只需要进行一次合并操作,因此,比动态批处理更加高效。静态批处理的另一个缺点在与,它往往需要占用更多的内存来存储合并后的几何结构。这是因为,如果在静态批处理钱一些物体共享了相同的网格,那么在内存中每一个物体都会对应一个该网格的复制品,即一个网格会变成多个网格在发送给GPU。如果这类使用同一网格的对象很多,那么这就会成为一个性能瓶颈了。例如,如果在一个使用了1000个相同模型的森林中使用静态批处理,那么,就会多使用1000倍的内存,这会造成严重的内存影响。
无论是静态批处理还是动态批处理,都要求模型之间需要共享同一个材质。但不同的模型之间总会需要有不同的渲染属性,例如,使用不同的纹理、颜色等。这是,我们需要一些策略来尽可能地合并材质。
如果两个材质之间只有使用的纹理不同,我们可以把这些纹理合并到一张更大的纹理中,这张更大的纹理被称为是一张图集(atlas)。一旦使用了同一张纹理,我们就可以使用同一个材质,再使用不同的采样坐标对纹理采样即可。
但有时,除了纹理不同外,不同的物体在材质上还有一些微小的参数变化,例如,颜色不同、某些浮点属性不同。但是,不管是动态批处理还是静态批处理,它们的前提都是要使用同一个材质。是同一个,而不是使用了同一种Shader的材质,也就是说它们指向的材质必须是同一个实体。这意味着,只要我们调整了参数,就会影响所有使用这个材质的对象,那么想要微小的调整怎么办?一种常用的方法就是使用网格的顶点(最常见的就是顶点颜色数据)来存储这些参数。经过批处理后的物体会被处理成更大的VBO发送给GPU,VBO中的数据可以作为输入传递给顶点着色器,因此,我们可以巧妙地对VBO中的数据进行控制,从而达到不通效果的目的。一个例子是,森林场景中所有的树使用了同一种材质,我们希望它们可以通过批处理来减少draw call,但不同树的颜色可能不同。这么,我们可以利用网格的顶点的颜色数据来调整。
Gpu instancing 要求是同一个mesh。一口气收集所有的obj信息上传上去,材质上的微小差距要写进自带的buffer中