Unity降低DrawCall的一些方法

1 UI方面:使用图集,降低drawcall
Batch:批渲染
基本原理就是通过将一些渲染状态一致的物体合成一个大物体,一次提交给gpu进行绘制
如果不batch的话,就要提交给很多次,这可以显著的节省drawcall,实际上这主要节省了cpu的时间,cpu从提交多次到提交一次,对gpu来说也不用多次切换渲染状态。
当然能batch的前提一定是渲染状态一致的一组物体。
简单说,使用软件把图集转移到一张大图片上会降低DrawCall,
这里推荐一下软件:
TexturePacker,free版本有水印,建议
***

2 模型方面:
批量上产Prefab的顺序也会影响到DrawCall的动态批处理
首先,创建了几个基本的Prefab,Capsule(胶囊体),Cube(立方体),Cylinder(圆柱体),Sphere(球体)。
1 无论采用何种加载顺序,Capsule,Sphere都无法动态批处理,因为这两个Prefab的顶点数量大于300,因此Unity无法批处理。
2 若连续加载两个都可以被批量处理的Prefab时,无论采用哪种加载方式都会被动态批处理
3 如果同时加载一个可以被批处理的Prefab,一个不可以被批处理的Prefab时,加载顺序的不同会影响DrawCall
4 在一个循环里同时加载两个Prefab,这里可以看到Cube并没有被动态批处理掉
4.1 -------------------------------------------------------------------------------------------------------------------------------------
5 :10个Cube调用一次动态批处理,但是10个球会调用10次,总批处理次数加起来就是11次,节省批处理9次。




一些UGUI的DrawCall方面的一些转载:

从UGUI的角度,如果你的UI中组件的材质与纹理均相同,这几个组件就可以被Batch。
CPU在传送资源信息给GPU时,只需要传一张大图就可以了,因为GPU可以在这张图中的不同区域进行采样,然后拼出对应的界面。注意,这就是为什么需要用同一个Source
1
Image图集的原因,是Batch的关键,因为一个Drawcall就把所有原材料传过去了,GPU你画去吧。

但是显然把所有图片打成一张图集是不合理的,因为这张图可能非常大,所以就要按照一定规则将图片进行分类。在分类思路上,我们希望做到Drawcall尽可能少,同时资源量也尽可能少(多些重用),但这两者某种程度上是互斥的,所以折衷一下,可以遵循以下思路:
1
设计UI时要考虑重用性,如一些边框、按钮等,这些作为共享资源,放在1~3张大图集中,称为重用图集;
1
其它非重用UI按照功能模块进行划分,每个模块使用1~2张图集,为功能图集;
1
对于一些UI,如果同时用到功能图集与重用图集,但是其功能图集剩下的“空位”较多,则可以考虑将用到的重用图集中的元素单独拎出来,合入功能图集中,从而做到让UI只依赖于功能图集。也就是通过一定的冗余,来达到性能的提升。
1
有了层级号之后,就要合并批次了,此时,Unity会将每一层的所有元素进行一个排序(按照材质、纹理等信息),合并掉可以Batch的元素成为一个批次,目前已知的排序规则是,Text组件会排在Image组件之前渲染,而同一类组件的情况下排序规则未知(好像并没什么规则)。经过以上排序,就可以得到一个有序的批次序列了。
这时,Unity会再做一个优化,即如果相邻间的两个批次正好可以Batch的话就会进行Batch。
1
举个栗子,一个层级为0的ImageA,一个层级为1的ImageB(2个Image可Batch)和一个层级为0的TextC,Unity排序后的批次为TextC->ImageA->ImageB,后两个批次可以合并,所以是2个Drawcall。
1
再举个栗子,一个层级为0的TextD,一个层级为1的TextE(2个Text可Batch)和一个层级为0的ImageF,Unity排序后的批次为TextD->ImageF->TextE,这时就需要3个Drawcall了!(是不是有点晕,再回顾下黑体字)
1

少用Mask
Mask对于uGUI性能来说是噩梦一般的存在,因为很可能因为这个东西,导致Drawcall数量成倍增长。

Mask实现的具体原理是一个Drawcall来创建Stencil
mask(来做像素剔除),然后画所有子UI,再在最后一个Drawcall移掉Stencil mask。
这头尾两个Drawcall无法跟其他UI操作进行Batch,所以表面上看加个Mask就会多2个Drawcall,
但是,因为Mask这种类似“汉堡包式”的渲染顺序,所有Mask的子节点与其他UI其实已经处在两个世界了,
上面提到的层级合并规则只能分别作用于这两个世界了,所以很多原本可以合并的UI就无法合并了。
1
所以,在使用uGUI时,有一些建议:
1
应该尽量避免使用Mask,其实Mask的功能有些时候可以变通实现,比如设计一个边框,让这个边框叠在最上面,底下的UI移动时,就会被这个边框遮住;
1
如果要使用Mask时,需要评估下Mask会带来的性能损耗,并尽量将其降到最低。比如Mask内的UI是动态生成的话(比如List组件),那么需要注意UI之间是否有重叠的现象。

总结:
1
uGUI的性能其实涉及到的方面很多,这里列出来的只是目前能想到的,因为个人能力有限,可能出些纰漏。对于文中的一些建议,这里整理一下得出一些最佳实践:

1 设计UI时要考虑重用性,如一些边框、按钮等,这些作为共享资源,放在1~3张大图集中,称为重用图集;
2 其它非重用UI按照功能模块进行划分,每个模块使用1~2张图集,为功能图集;
3 对于一些UI,如果同时用到功能图集与重用图集,但是其功能图集剩下的“空位”较多,则可以考虑将用到的重用图集中的元素单独拎出来,合入功能图集中,从而做到让UI只依赖于功能图集。也就是通过一定的冗余,来达到性能的提升。
4 有相同材质和纹理的UI元素是可以Batch的,可以Batch的UI上下叠在一块不会影响性能,但是如果不能Batch的UI元素叠在一块,就会增加Drawcall开销。
5 要注意UI元素间的层叠关系,建议用“T”工具查看其矩形大小,因为有些图片透明,但是却叠在其它UI上面了,然后又无法Batch的话,就会无故多许多Drawcall;
6 UI中出现最多的就是Image与Text组件,当Text叠在Image上面(如Button),然后Text上又叠了一个图片时,就会至少多2个Drawcall,可以考虑将字体直接印在下面的图片上;
7 有些情况可以考虑人为增加层级从而减少Drawcall,比如一个Text的层级为0,另一个可Batch的Text叠在一个图片A上,层级为1,那此时2个Text因为层级不同会安排2个Drawcall,但如果在第一个Text下放一个透明的图片(与图片A可Batch),那两个Text的层级就一致了,Drawcall就可以减少一个。
8 应该尽量避免使用Mask,其实Mask的功能有些时候可以变通实现,比如设计一个边框,让这个边框叠在最上面,底下的UI移动时,就会被这个边框遮住;
9 如果要使用Mask时,需要评估下Mask会带来的性能损耗,并尽量将其降到最低。比如Mask内的UI是动态生成的话(像List组件),那么需要注意生成的UI之间是否有重叠的现象;
10 有空好好看下Unity GUI层级合并规则与批次生成规则这一节。
1
作者:kingshijie
链接:http://www.jianshu.com/p/061e67308e5f 來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

猜你喜欢

转载自blog.csdn.net/weixin_38531633/article/details/104433999