Unity静态合批


前言

之前写这篇笔记的时候,对静态合批也是半知半解。最近也就稍微细的了解了一下所谓的静态合批究竟是个啥,在此作下笔记。

静态合批就属于那种听上去很常用很实用,但是实际上并没有很多手游使用的优化方式(端游上常用)。



批量渲染

批量渲染又叫做合批,是一种通过减少DC来提升逻辑线和渲染线整体效率的方法。但这是建立在GPU相对空闲,而CPU把更多的时间都耗费在渲染命令的提交上时,才有意义。因为如果瓶颈在GPU,比如GPU性能偏差,或片段着色器过于复杂等,此时GPU本身就需要满负荷工作,那么没准适当减少批处理,反而能达到优化的效果。

所以要做性能优化,还是应该先定位瓶颈到底在哪儿,然后再考虑优化方案,而不是一股脑的就合批。当然,通常情况下,确实是以CPU出现瓶颈更为常见。



合并网格

静态合批最关重要的一件事就是合并网格。

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

在Unity中,直接勾选物体的static(自动静态合批)或者通过代码调用合并函数(手动静态合批),均可以实现网格合并。

Unity会把合并网格的相关信息存在场景文件(.scene)下,所以对于那些存在静态物体的场景文件一般来说会大很多。

因此静态合批实际上是属于空间换时间的一种策略。并且不仅仅是文件增大,在运行时,静态合批的网格会常驻内存,如果存在大量的静态合批网格,那么内存压力会十分可怕。

还有一点需要注意,不同引擎、平台对于最终合并网格生成的大网格顶点数和索引数是有限制的。一旦超过了限制,就会合并成另一个新的大网格。



批处理

静态合批虽然通过合并网格生成了新的大Vertex Buffer和Index Buffer,从而可以在一个批次中提交顶点信息,但是这并不意味着这一个批次中只有一个DC。也就是说,虽然静态合批可以有效地减少批次,但是可能无法减少DC。

举个例子,当一个合并过的网格中某一部分发生剔除或是被隐藏时,其对应Vertex Buffer和Index Buffer并不会被修改。引擎会选择将整个大网格拆分成若干个小部分来进行分次渲染,每次小渲染都是一个DC,通过调整每个DC来跳过不显示的内容。

Unity物体的静态设置 unity 静态_批处理

即使是一个批次中存在多个DC,但由于这些DC之间没有渲染状态的切换,所以渲染效率还是很高的。



比较

小网格+静态合批 vs 大网格

1、静态合批可以通过主动隐藏部分对象(算是手动剔除)来减少GPU对顶点信息的处理(不会送到渲染管线中),即之前提到的一个批次多个DC的方式;而大网络则无法实现。

2、静态合批可以通过参与剔除来减少GPU对顶点信息的处理(不会送到渲染管线中),也是之前提到的一个批次多个DC的方式;而大网络必须全部计算全部顶点信息,到最后被剔除的部分虽然都会被丢弃,但仍然参与了部分的计算,属实有些浪费。



参考

https://indienova.com/u/gadqq/blogread/27660