Unity UI优化小结

https://zhuanlan.zhihu.com/p/43111806

最近在做Unity的项目,负责UI相关的工作,学习了一下Unity UGUI更新的原理,以及优化相关的部分。本文主要参考UWA的分享,UWA专注性能优化,感觉有很多值得学习的文章, UWA - 简单优化、优化简单 ,打好理论基础,少走弯路,后面实际项目中就是尽可能去实现这些细节了。

目录

  • 1.元素更新方式
  • 2.Draw Call合并规则
  • 3.网格更新机制
  • 4.降低界面的渲染开销
  • 5.降低界面的更新开销

1.元素更新方式

UGUI

public class VertexHelper:IDisposable
{
    private List<Vector3> m_Position = ListPool<Vector3>.Get();
    private List<Color32> m_Colors = ListPool<Color32>.Get();
    private List<Vector2> m_Uv0S = ListPool<Vector2>.Get();
    private List<Vector2> m_Uv1S = ListPool<Vector2>.Get();
    private List<Vector3> m_Normals = ListPool<Vector3>.Get();
    private List<Vector4> m_Tangents = ListPool<Vector4>.Get();
    private List<int> m_Indices = ListPool<int>.Get();
}

有这样一个VertexHelper类,和UI元素有一一对应的关系,包含顶点信息,UV,颜色,等等 当UI元素发生变化的时候,就会从位置,长宽等数组填充这些list。

对制作的影响

当UI发生改变的时候,须要对数组的元素进行更新, *“动态元素”少用Outline,Tiled Sprite *尽量减少“动态”长文本

image

如上图Tiled生成了大量网格,在填充的时候耗时更长。 OutLine,是通过把一个四边形重复5次,画出的OutLine的效果,会使文本的定点数乘以5,使更新的数组过长。

更新方式

  • UIPanel.LateUpdate

  • 轮询

  • UIPanel.UpdateWidgets

  • Cavans.SendWillRenderCanvas

  • 队列

  • m_LayoutRebuildQueue

  • m_GraphicRebuildQueue

NGUI每帧更新UIPanel,轮询,不管发生变化与否,哪怕是静态的,还是会有开销

UGUI更新包含2个队列,渲染之前在SendWillRenderCanvas的回掉里面处理2个队列的元素,如果大量静态,消耗几乎为0。

对动态HUD缓存机制的影响

  • NGUI

  • 适量元素:Color.a= 0,移出

  • 大量元素:SetActive(false)

  • Time + 二级缓存

  • UGUI

  • Scale = 0, Alpha Group = 0

如血条,伤害数字,经常会出现消失的UI元素,如果出现就创建,消失就destory,开销会非常大。所以通常的做法通过缓存,如果通过SetActive有时候会有额外的开销,

UGUI通常的操作方式可以通过scale = 0 ,或则Alpha Group为0,可以快速隐藏,不要直接alpha = 0 ,在draw call 上是没变化的,实际上还是画了个透明度为0的面片。

NGUI中和UGUI相反,如果设置alpha = 0 ,是会把顶点移除掉,可以减少setActive的开销。

2.DrawCall 合并规则

渲染顺序

  • NGUI: Depth

  • 设置depth值,以UIPanel为单位,按照大小进行排序,相同材质进行合并

  • UGUI:hierarchy

  • 重叠检测

  • 分层合并

存在优势,也有一些问题,UGUI的合并规则是进行重叠检测,然后分层合并。下面的例子中,不同颜色代表不同图集。

image

第一个图,4种颜色,左边和右边数序相同,蓝色是0层,白色都是1层,这样会分层合批成4个DrawCall。

第二个图,左边的蓝色是0层,右边的黑色是0层蓝色是1层,这种情况下不会合批,所以会是9个drawCall

第三个图,把黑色延长到重叠的地方,黑色同处0层, 所以DrawCall又降到了5。

所以在制作UI的时候,须要考虑层级关系,结合UGUI的合批规则,这样可以达到对drawCall的优化,

调试工具

  • NGUI:DrawCall tool
  • UGUI:Frame debugger

NGUI 可以通过DrawCall tool看到多少个三角面,多少个widgets,通过观察widgets的关系,对NGUI层级直接调整,来进行合批。

NGUI使用drawcall tool,通过调整index,把相同材质的放在同一层。

UGUI用frame Debug看每个drawcall绘制了哪些东西,再做调整

image

对界面的影响

  • UGUI

  • 不规则图标的摆放

  • UI元素的旋转

  • 动态遮挡

  • 3D UI

  • NGUI

  • 手动排序

UGUI中,对于不规则图形,视觉上icon没有重叠,但是UI层是包围盒的形式,Icon重叠了,UGUI在判断的时候没办法进行合并。

UGUI对于发生旋转的UI,包围盒是会发生重叠,会限制UGUI在合并DrawCall的操作。

如下图:

image

NGUI把不同的元素设在一个图集中,进行同批次绘制。

3.网格更新的机制

  • UIPanel.LateUpdate 两种更新方式

  • UIPanel.FillDrawCall 更新单个DrawCall

  • UIPanel.FillAllDrawCall 更新所有DrawCall

  • Canvas.BuildBatch 更新所有DrawCall

  • WaitingForJob 子线程网格合并

  • PutGeometryJobFence

  • BatchRendere.Flush UI如果开多线程渲染,BatChRender.Flush会增高,主线程在等待子线程的结果时Flush会等待。

NGUI根据不同的DrawCall 合并不同的网格 UGUI以Canvas为单位,一个Canvas下的元素,合并成一个Mesh,不同的UI元素会以SubMeshes的形式存在。UGUI中如果一个Canvas中有很复杂的动态元素,尽量将静态元素拆分出来,确保更新的效率。

image

优化方法:

  • UGUI

  • 拆分Canvas

  • NGUI

  • 控制FillAllDrawCalls

  • 拆分UIPanel

性能比较

  • 功能界面的DrawCall控制 NGUI>UGUI (NGUI通过DC树,通过调整Index进行调整)
  • 功能界面的网格更新机制 NGUI>UGUI (UGUI更新任何一个UI,都会更新整个Canvas)
  • 动态HUD界面的网格更新机制 UGUI>>NGUI (UGUI在处理动态UV的元素,如血条,动态UI会更有优势)
  • 堆内存控制 UGUI>>NGUI (NGUI堆内存占用更高)

参考 https://blog.uwa4d.com/archives/Implosion.html

4.降低界面的渲染开销

  • Profiling 定位
  • DrawCall 控制
  • Mesh.CreateVBO UI变化的网格开销
  • Overdraw UI比较容易产生Overdraw

Profiling

UGUI 非多线程渲染Unity5.3 主要集中在RenderSubBatch,

image

DrawCall控制

Z值!=0

合并时只会合并相邻层级,相同图集的元素

左边的图,4个血条红色和白色的z值相同,共2个drawcall,但是右边的图,红色和白色穿插,变成8个drawcall,在3D UI的时候尤其明显,2DUI不要通过这种方法,改Z值,因为2D改了之后,

image

未“隐藏” 的元素

包含 Null Sprite, Color.a = 0 屏幕外

对于隐藏的元素,NGUI的image组件中,alpha为空和sprite为空,都是占用drawcall渲染的,而且会打断前后的drawcall,穿插在上下2个元素中间的时候。

image

Hierarchy 穿插+重叠

如下图红点和Icon在不同图集中,如果红点稍微大一点,遮挡了旁边的Icon,就不能合批,须要调整Icon和红点的节点关系,4个Icons放在一个节点下,4个红点放在一个借点下。在同步位置的时候可能稍微麻烦有点,须要写个脚本同步位置。

image
image

图集分离

可能因为压缩方式的不同,导致UI的sprite在不同图集中,也会影响渲染开销,不同图集中无法进行合批

image

OverDraw

  • 减少UI层叠
  • 遮挡场景时,关闭场景相机
  • 不用Image检测事件

参考: https://blog.uwa4d.com/archives/video_UI.html

5.降低界面的更新开销

  • 动静分离
  • 降低更新频率
  • 避免“敏感”操作
  • 优化选项

动静分离

在UGUI中细分Canvas 下图中,血量和经验条会经常更新,如果在一个canvas中,PutGeometryJbFence和WaitngForJob,buildBatch出现的时候,表示更新的开销在子线程中,主线程处在一个等待的状态,差不多有5,6毫秒的等待。

image

拆分之后刚才的WaitingForJob等都没有了,动态的canvas开销就会很小。

image

降低更新的频率

  • 设定移动阈值
  • 设定更新频率
image

比如像小地图这样的界面,可能移动了一小段距离,小地图上更新了也不明显,可以通过设定阈值的方法,降低开销,或者直接设定更新时间。

避免“敏感”操作

  • 元素的Position赋值->Canvas.BuildBatch

下面的一个例子是在Canvas中,所有元素基本是静态的,但是有个元素,在Update中,会跟随target的position,每次发送改变的时候,会重建整个canvas,导致资源的浪费。

image

参考文献

https://blog.uwa4d.com/

[《聚爆Implosion》性能精析 UI部分]

UGUI研究院之全面理解图集与使用

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,589评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,615评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,933评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,976评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,999评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,775评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,474评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,359评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,854评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,007评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,146评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,826评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,484评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,029评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,153评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,420评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,107评论 2 356

推荐阅读更多精彩内容