静态合批
引自:关于静态批处理/动态批处理/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)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了