• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Unity 性能优化基础

武飞扬头像
虫虫!
帮助1

前言

最近笔者在找工作,面试过程经常被问到工作中做过哪些性能优化。这篇文章用以总结记录笔者在项目开发过程中,针对性能问题,需要注意的一些点。以及项目后期针对一些常见的影响性能的点做的一些优化。


一、代码层面

主要关注点:避免频繁申请堆内存,避免在一帧内进行大量耗时操作。

1)使用成员变量缓存,空间换时间
比如UI界面的节点用成员变量缓存起来,只用在初始化的时候获取一次。
比如每次计算红点逻辑保存到红点管理类的字典里,避免重复计算。
比如从表里频繁获取某些数据,获取后缓存起来,避免每次遍历整个表。
比如字符串拆分操作非常耗费性能,只拆分一次,然后缓存起来重复使用。
2)for/while等循环内,以及帧更新中避免创建内存,避免使用foreach。
3)使用泛型方法,避免装箱拆箱。
4)创建List和Dictionary时指定大小,避免内部扩容创建新数组。
5)使用StringBuilder进行字符串拼接。
6)使用对象池,回收可重复利用的对象,避免频繁创建和销毁对象。
7)在在网络IO中使用单独的线程来收发网络数据,使用循环缓冲区缓存数据。
8)耗时操作,异步处理,或者使用协程将消耗分散到每一帧。
9)一些不重要的刷新进行限帧操作,比如未参加战斗的怪物每5帧刷新一次。
10)去掉脚本中的空Update,空Update也会调用有额外性能消耗。

二、减少Rebatch和Rebuild

Unity会把要绘制的UI信息保存在Vertexhelper中,并且调用CanvasRenderer里面的方法进行绘制。
UGUI中的Canvas负责把它们包含的Mesh合批,生成合适的渲染命令发送给Unity图形系统。以上行为都是在Native C 代码中完成,我们称之为Rebatch或者Batch Build,当一个Canvas中包含的几何体需要Rebacth时,这个Canvas就会被标记为Dirty状态。
我们可以在Profiler中通过查看标志性函数Canvas.willRenderCanvases的耗时,来了解Mesh重建的性能消耗。

先简单说说什么是DrawCall和Batch:

DrawCall
即绘制调用命令,CPU在准备好渲染数据并设置渲染状态后,会通过Drawcall命令通知GPU进行渲染。

实际发送绘制指令之前,我们需要设置好所有必须的GPU状态,例如:Mesh数据(顶点位置、顶点法线等顶点数据)、着色器代码、纹理数据、混合设置以及其他的着色器属性等。这些都是在CPU上进行。

Batch
一些设置状态、改变状态的指令再加上一或多个绘制指令构成了我们所说的一次Batch。

可以点击Game窗口的Stats查看Batch的数量:
学新通

1.Rebatch

Rebatch发生在C 层面,是指Canvas分析UI节点生成最优批次的过程,节点数量过多会导致算法(贪心策略)耗时较长。对应SetVerticesDirty,当一个canvas中包含的Mesh发生改变时就触发,例如SetActive、transform的改变、 颜色改变、文本内容改变等等,canvas独立处理,互相不影响。消耗在对meshes按照深度和重叠情况排序、共享材质的检测等。

Batch以Canvas为单位,同一个Canvas下的UI元素最终都会被Batch到一个Mesh中。Batch前,UGUI根据UI材质以及渲染顺序重排,在不改变渲染结果的前提下,尽可能将相同材质的UI元素合并在同一个SubMesh中,以减少DrawCall。Batch只在UI元素发生变化时进行,合成的Mesh越大,耗时越大。重建对Canvas下所有ui元素生效,不论是否修改过。

5.2之后底层是多线程的,考虑到现在手机上都是多核,这部分消耗可能会小很多。不过对于复杂的UI,还是应该注意这块的消耗。

合批细节
1.计算每个渲染节点的深度depth
1)按照在Hierarchy节点的顺序,从上向下进行depth分析(深度优先原则);
2)跳过不用渲染的节点,比如active为false,image脚本Disable,Canvas不渲染的Layer等;
3)如果处于渲染状态且(网格)没有覆盖到其他节点,depth = 0;
4)处于渲染状态但是覆盖到其他节点,找到被覆盖节点中depth最大的元素A。
5)若节点的材质和贴图是否和A相同,则节点的depth等于A节点。否则A节点depth 1;

2.根据节点的depth、材质(获取Instance ID)、贴图(Instance ID)对节点进行排序。
根据排序结果对depth、材质、贴图都相同的节点进行合批。
注意节点Position.z不为0时,视为3D UI,其子物体全部不参与合批,且打断前后合批。

2.Rebuild

Rebuild发生在C#层面,是指UGUI库中layout组件调整RectTransform尺寸、Graphic组件更新Material,以及Mask执行Cull的过程,耗时和发生变化的节点数量基本呈线性相关。

只有LayoutGroup的直接子节点,并且是 Graphic类型的(比如 Image 和 Text)会触发SetLayoutDirty。

Graphic改变的原因包括,基本的大小、旋转以及文字的变化、图片的修改等等,对应SetMaterialDirty。

发生Rebuild时会触发Rebatch。

3.优化点

1.Canvas动静分离,合理划分,按游戏类型和UI数量划分,太多也有额外消耗。
举例:跑马灯效果,可以在动态节点的父节点添加一个单独Canvas。

2.减少节点层次和数量,使用相同材质贴图的UI尽量保持深度相同,减小合批计算量。
举例:可以将一个Text的层级下面放一个其他图集的透明图片,将其层级垫高,使其与相同depth的Text节点进行合批。

3.修改Image的Color属性,原理是修改顶点色,会引起网格Rebuild,从而触发Rebatch。
可以通过修改shader颜色来实现,不会重绘,材质不变,没有Rebatch。
举例:颜色的渐变效果(颜色动画)可以通过动态修改材质的shader颜色来实现。

4.RectMask2D代替Mask。

5.少用layout,简单的布局RectTransform代替。

6.不显示的对象,不要SetActive,设置Canvas Group的alpha为0,scale为0,这样vbo(在显存中保存的 顶点信息)不会被清除。
或者CanvasRenderer.cull设为true,表示当UI的透明度为0的时候删掉网格和顶点。

7.使用图集,同个界面、同个功能的图在同一个图集。

8.慎用自带组件Outlien和Shaow,都是通过重复绘制多个Mesh实现的,其中Showdow绘制为原文本Mesh的2倍,而Outline为5倍,对渲染面数、顶点数,BuildBatch和SendWillRenderCanvases的耗时,Overdraw都有影响。

可以使用BMFont制作美术字。若对于某种字体每次出现都需要这两种效果,可以让美术同学直接把阴影和描边做到字体里。

三、降低OverDraw

Overdraw是指一帧当中,同一个像素被重复绘制的次数。Fill Rate(填充率)是指显卡每帧每秒能够渲染的像素数。在每帧绘制中,如果一个像素被反复绘制的次数越多,那么它占用的资源也必然更多。Overdraw与Fill Rate成正比,目前在移动设备上,FillRate的压力主要来自半透明物体。因为多数情况下,半透明物体需要开启 Alpha Blend 且关闭 ZTest和 ZWrite,同时如果我们绘制像 alpha=0 这种实际上不会产生效果的颜色上去,也同样有 Blend 操作,这是一种极大的浪费。

1.减少UI重叠层级,隐藏处于底下被完全覆盖的UI面板。
2.对于需要暂时隐藏的UI,不要直接把Color属性的Alpha值改为0,UGUI中这样设置后仍然会渲染,应该用CanvasGroup组件把Alpha值置零。
3.需要响应Raycast事件时,不要使用空Image,可以自定义组件继承自MaskableGraphic,重写OnPopulateMesh把网格清空,这样可以响应Raycast而又不需要绘制Mesh。
4.打开全屏界面,关闭场景摄像机。对于一些非全屏但覆盖率较高的界面,在对场景动态表现要求不高的情况下,可以记录下打开UI时的画面,作为UI背景,然后关掉场景摄像机。
5.裁掉无用区域,镂空,对于Sliced类型的Image可以看情况取消Fill Center。
6.慎用Mask组件和Outline、Shadow组件

总结

代码层面只要是空间换时间,避免频繁申请堆内存,避免在一帧内进行大量耗时操作。
UGUI层面:主要是降低DrawCall、减少Rebuild、减少OverDraw。

参考:
UGUI DrawCall合批细节
https://edu.uwa4d.com/lesson-detail/126/482/0?isPreview=false
https://zhuanlan.zhihu.com/p/340480771
https://blog.csdn.net/wanttokonw/article/details/121889261
Unity官方的UGUI优化指南读后总结
UGUI深入理解–性能优化总结
NGUI和UGUI对比及性能提升技巧
UGUI性能优化总结(花卷)

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgghaei
系列文章
更多 icon
同类精品
更多 icon
继续加载