Unity优化之Drawcall

一、什么是Drawcalls

在Unity中,每次CPU准备数据并通知GPU的过程就称之为一个DrawCall。这个过程会指定一个Mesh被渲染,绘制材质。

二、Drawcalls有什么影响

为了CPU和GPU可以进行并行工作,需要一个命令缓冲区,由CPU向其中添加命令,然后由GPU从中读取命令,这样就实现了通过CPU准备数据,通知GPU进行渲染。在每次调用DrawCall之前,CPU需要向GPU发送很多内容,主要是包括数据,渲染状态,命令等。所以如果DrawCall数量过多就会导致CPU进行大量计算,进而导致CPU的过载,影响程序运行效率。

三、查看Drawcalls

在unity中查看drawcalls有2个方法,如图1所示查看Game窗口中的State下的Batces,这个数量和drawcalls数量相同。第二种方法是查看Window  → Analysis → Profiler 中的Rendering下的Drawcalls,如图2所示。 

Unity优化之Drawcall_第1张图片

图1                                                                                图2

四、Drawcalls优化

1. 3D场景优化

1.1 静态批处理

静态批处理首先需要到 Project Setting → Player → Other Setting 中将Static Bathing 勾选上,然后把需要静止的物体标记为Static,然后无论大小,相同材质的都会组成Batch。如下图所示,当没有勾选 static 的时候,场景中2个cube的drawcalls为4,勾选了之后drawcalls变成了3。

Unity优化之Drawcall_第2张图片

1.2 动态批处理

动态批处理需要在Project Setting → Player → Other Setting 中将Dynamic Bathing 勾选上,Unity会自动将使用相同材质的物体合并处理。如图所示,场景中虽然有3个cube,但是drawcalls还是只有3。

Unity优化之Drawcall_第3张图片

不过,在使用动态批处理的时候,具有一些局限性。

  • 顶点属性最大限制900的可移动物体,

  • 使用lightmap的物体不行进行批处理

  • 使用多通道的shader也不会进行批处理

  • 缩放比不同的物体不会批处理

1.3 勾选 Enable GPU Instancing

在使用大量重复的物体时,需要将该物体的材质的 Enable GPU Instancing 勾选上,这样Unity会将Mesh相同的物体合并处理,常用于树木,植被,粒子等。如图所以虽然我放置了5个cube,但是drawcalls依然只有3。

正在上传…重新上传取消

1.4 减少实时光照和阴影效果

当开启灯光,在没有开启阴影的时候drawcalls为3,开启了之后drawcalls变成了7。实时阴影会导致drawcalls大幅上升,建议关闭实时阴影,使用lightmap满足你想要的阴影效果。

Unity优化之Drawcall_第4张图片

1.5 合并Mesh和材质球

如果一个模型有2个或者以上的材质球的时候,drawcalls会直线上升,所以应该劲量将mesh和材质球合并成为一个,以减少drawcalls。如图所示我在一个测试cube中放置了3个material,这个时候drawcalls从3变成了10(和不同的material有关,每个material最低为1)。

Unity优化之Drawcall_第5张图片

1.6 渲染顺序调整

Unity的渲染是有顺序的,这个顺序我们可以自己调整,相机按照深度进行渲染。在图中我使用了3个cube梯次排序,其中第一个和第三个使用相同的材质球。当第二个cube在中间时,drawcalls为5,第二个cube在前或者后时,drawcalls为4。

Unity优化之Drawcall_第6张图片

出现图中情况的原因是在绘制第一个cube时候使用材质球A,绘制第二个cube的时候使用材质球B,绘制第三个cube的时候使用材质球A,这个时候第二个打断了材质球A的渲染使用,使第一个和第三个材质球分开渲染了。

2. 2D UI优化

2.1 图集制作

在制作UI的时候,文件夹中小的图片可以在Unity中制作成图集再给UI使用,这样可以减少drawcalls,具体操作为首先在Project Setting →Editor → Sprite Packer 中选择Mode 为Enable。然后在Assets中右键 Create → Sprite Altas,再将需要打包图集的图片资源拖到Altas中的Objects for Packing中,再点击Pack Preview,图集就制作好了。

如图所示,在没有使用图集的时候,3张图drawcalls为5,当使用的图集时,drawcalls变成了3,3个图使用同一张图集,drawcalls也就变成了3。

Unity优化之Drawcall_第7张图片

2.2 不同图集重叠会打断合批

不同的图集之间重叠会打断合批,在制作UI的时候应该注意不同的UI放置位置,避免出现这种问题,如图,2个图集的UI在分开放的时候drawcalls为4,重叠隔开之后drawcalls变成了5。

Unity优化之Drawcall_第8张图片

2.3 谨慎使用多canvas

每添加一个canvas会添加一个drawcalls,哪怕你下面的资源使用同一个图集也会添加。如图所示当我添加一个canvas,改变了第三个图的层次之后,drawcalls从3变成了4。

Unity优化之Drawcall_第9张图片

2.4 Mask会打断合批,新增drawcalls

当我给使用了图集的一个UI添加一个Mask组件之后,drawcalls从3变成了5。这里可以使用Rect Mask 2D,效果相同但是drawcalls不会增加,回到了3。当我在有Mask组件的UI下添加一个Image,sprite还是使用图集中的图片时,发现drawcalls从5变成了6,说明mask组件还会打断合批,使Mask内外资源分开渲染。这个时候将Mask改为Rect Mask 2D,drawcalls从6变回4,但是也比最初的3多了1,说明使用Rect Mask 2D 也会打断合批,分开渲染。

Unity优化之Drawcall_第10张图片

2.5 图文混排打断合批

新加入两个Text文本(Text Mesh Pro效果相同),drawcalls从3变到4,因为text和image有不同写渲染方式需要分开渲染,移动Text,当2个Text打断了图的连续深度排序时,图片的合批会被,打断,生成多的drawcalls,在图文排版是应特别注意。下图列举了一些错误排版方式和正确方法以及建议排版。注意,unity必须重叠,才会多产生drawcall

正确:

Unity优化之Drawcall_第11张图片

错误:

Unity优化之Drawcall_第12张图片

Unity优化之Drawcall_第13张图片

建议:

Unity优化之Drawcall_第14张图片

GPU instance 使用一次渲染调用来绘制多个物体,来节省每次绘制物体时CPU→GPU的通信

使用限制 优点
静态合批 静止的问题,大内存,大包体 StaticBatchingUtility.Combine 适用范围较广
动态合批 * 顶点属性最大限制900,
* 使用lightmap的物体不行进行批处理
* 使用MultiplePass的shader也不会进行批处理
在一些动的物体上面,内存不会显著增长,不会影响打包的包体
GPUInstance 一般用于大批生成的物体 没有动态合批那样对网格数量的限制,也没有静态网格那样需要这么大的内存
SRP Batcher 不同mesh,只要使用相同shader且变体一样即可 缺点:constant Buffer显存固定开开销,不支持 节省Uniform Buffer的写入操作;按shader分 Batch,预先生存Uniform Buffer,Batch 内部无CPU Write

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