Unity静态合批处理详解

静态批处理的原理

静态合批最重要的一件事就是合并网格。
在运行前 或是 发布前,场景中相同材质,并且标记为 Batching Static(自动静态合批)或者通过代码调用合并函数(StaticBatchingUtility.Combine 手动静态合批)的物体,引擎会把网格信息取出来,之后对网格上的顶点进行空间变换,变换到同一坐标系下,合并成一个新的大网格。

形成新的大Vertex Buffer Object(VBO 顶点缓冲对象)和Index Buffer Object(IBO 索引缓冲对象)(这两个缓冲区一旦确定了就不会再被修改了),最终会在一个批次中提交这些顶点信息。(如果之后需要对合并的网格进行空间变换,由于已经在同一坐标系了,所以直接对合并的节点进行矩阵变换即可)。

静态批处理到底会不会减少DC

这个缓存会记录着每一个 渲染对象的 IBO 的范围,然后在遍历每个渲染对象前,先设置他们同一个渲染状态(也就是材质信息要一致的原因),然后再逐个遍历渲染对象的 IBO,再调用类似 glDrawElement 的 API 来绘制即可,绘制前,要判断这个 渲染对象时是否在视锥体内,如果不在,就不绘制。所以静态合批不是减少 DC,而是减少 DrawState 的设置,在 unity 就是减少 SetPassCall 的设置

静态合批虽然合并网格,从而在一个批次中提交更多的顶点信息,虽然可以有效减少Batch次数和渲染状态SetPassCall的改变次数。但是这并不意味着这一个批次中只有一个DC。

举个例子,在一个合并过的网格中,因为场景中物体的可见性,需要大网格中的某一部分发生剔除或是被隐藏时,其对应Vertex Buffer和Index Buffer并不会被修改,引擎会选择将整个大网格拆分成若干个小部分来进行分次渲染,每次小渲染都是一个DC,通过调整每个DC来跳过不显示的内容,由于这些子物体共享Material,所以渲染状态/绘制命令并没有切换,调用DC时会缓存绘制命令到Command Buffer,还是起到了优化的目的。

所以静态合批并不减少Draw call的数量但是在编辑器时由于计算方法区别Draw call数量是会显示减少了的,但是由于我们预先把所有的子模型的顶点变换到了世界空间下,并且这些子模型共享材质,所以在多次Draw call调用之间并没有渲染状态的切换,渲染API会缓存绘制命令,起到了渲染优化的目的。另外,在运行时所有的顶点位置处理不再需要进行计算,节约了计算资源。

静态批处理的劣势

Unity会把合并网格的相关信息存在场景文件(.scene)下,所以对于那些存在静态物体的场景文件一般来说会大很多。并且不仅仅是文件增大,在运行时,静态合批的网格会常驻内存,如果存在大量的静态合批网格,那么内存压力会十分可怕。它实际上是属于空间换时间的一种策略。由于静态合批的Buffer既增加运行时内存又增加包体,所以还可以采取运行时进行静态合批的策略,用第一次加载的内存和时间换包体大小。

参考游戏图形批量渲染及优化:Unity静态合批技术 | indienova 独立游戏

【Unity游戏开发】合批优化汇总 - 知乎

unity 减少drawcall_unity scroll - 腾讯云开发者社区-腾讯云

关于静态批处理/动态批处理/GPU Instancing /SRP Batcher的详细剖析 - 知乎

你可能感兴趣的:(Unity通用,unity,游戏引擎)