静态合批

引自:关于静态批处理/动态批处理/GPU Instancing /SRP Batcher的详细剖析 - 知乎 (zhihu.com)

在inspector面板的static打钩,在Build的时候Unity会自动提取这些共享材质的模型的Vertexbuffer和indexbuffer,将这些数据变换到世界空间下,存储在新构建的大VertexBuffer和IndexBuffer中(内存占用翻倍),并且记录每一个子模型的Index buffer数据在构建的大Index buffer中的起始及结束位置。

 

在后续的绘制过程中,一次性提交整个合并模型的顶点数据,根据引擎的场景管理系统判断各个子模型的可见性。然后设置一次渲染状态,调用多次Draw call分别绘制每一个子模型。

或者手动调用 StaticBatchingUtility.Combine(tranHexHolder.gameObject);,在运行时静态合批(对单个物体的shader参数有修改会打断合批),可以在在刷新完所有物体材质状态后再次调用。

调用这个API会将绑定物体的所有子物体的网格合并成一个(不考虑material),但setpasscall还是分成多个,unity还提供了一个可以自己设置哪些物体合并的接口:

StaticBatchingUtility.Combine(GameObject[] gos, GameObject staticBatchRoot); 感觉把相同材质的mesh合并才是最优的,但实测setpasscall略有降低,batch升高很多,要根据项目情况选择哪种方式。

在静态合批后更改材质参数(shader),或者重新赋材质无需重新调用合批函数(网格只需要生成一次),unity会自己根据相同的材质分批发送drawcall,比如合批后十个物体共享两个材质,drawcall显示的2,在运行时将十个物体的材质换成一个,那drawcall显示的是1。

与直接使用大网格的不同

1.静态合批可以主动隐藏部分对象。静态合批在运行时,由于每个参与合并的对象可以通过起始索引等彼此区分,因此可以通过上述多次Drawcall的策略,实现隐藏指定的对象,而大网格不可以。

2.静态合批可以有效参与CPU的视锥剔除。剔除后,被送进渲染管线的顶点数量就会减少,也就意味着顶点着色器处理的顶点会减少,而使用大网格渲染时,由于整个网格都会被送进渲染管线,因此每一个顶点需要被顶点着色器处理,如果摄像机智能照到一点点,那么绝大多数参与计算的顶点都会被裁减掉,有一些浪费。

合批条件:

1.合批的物体不能移动旋转缩放,(更改材质参数会导致创建一个新的材质实例,虽然不会重新创建网格,但会增加drawcall),但是staticBatchRoot 可以移动。

2.只有使用同一材质球实例的物体可以合批。

3.合并后的顶点数最大65535,超过就会自动分成多个。

4.导入的模型需要开启可读写。

原理:

优化点:并不减少drawcall,由于预先把所有子模型的定点变换到世界空间下,运行时cpu不需要再次执行定点变换操作,节约了少量的计算资源,并且这些子模型共享材质,所以在多次drawcall调用间没有渲染状态的切换,commaderbuffer会缓存命令统一传给gpu,起到渲染优化的目的。

 

commaderbuffer动态图:【Unity游戏开发】合批优化汇总 - 知乎 (zhihu.com)

posted @ 2023-02-27 15:12  mc宇少  阅读(216)  评论(0)    收藏  举报