转自:http://www.jianshu.com/p/5b6f5022662e

开发过程中对UGUI的一个小总结。

首先从原画师拿到效果图,美术切图,拿到碎图后打成大图。

我们先来说一下图:RGBA8888:每一个通道占8位。大图:1024*1024。高端    机:2048*2048。

我们通常从美工那里拿来碎图,歪歪使用的一个工具texturepacker 把碎图打成大图,导出成 .tpsheet  .png格式。其次我们要做的是,在Unity3d中导入插件texture import(此插件会自动把大图打成图集).然后把大图导入U3D。

在UI优化中较为明显而众所周知的就是降低DrawCall(注释:DrawCall CPU向GPU发送的一次渲染指令)。而降低DrawCall我们会采用静态合批和动态合批。(注释:合批必须同类型 Mesh 同材质。)DrawCall的标准 RGP 类 小于 150。

然而,工作中我们优化大概分为UI层级计算,UI重建和多层级渲染。接下来我们来说一下:

UI层级 计算 :

1,计算层级:

1,如果有一个UI元素,它所占的屏幕范围内(通常是矩形),如果没有任何UI在它的底下,那么它的层级号就是0(最底下);

2,如果有一个UI在其底下且该UI可以和它Batch,那它的层级号与底下的UI层级一样;

3,如果有一个UI在其底下但是无法与它Batch,那它的层级号为底下的UI的层级+1;

4,如果有多个UI都在其下面,那么按前两种方式遍历计算所有的层级号,其中最大的那个作为自己的层级号。

合并批次原则;

同层级{同材质球,}

{0 : { image   , image, text  }}

1,Unity会将每一层的所有元素进行一个排序(按照材质、纹理等信息),合并掉可以Batch的元素成为一个批次

2,Text组件会排在Image组件之前渲染。

3,,Unity会再做一个优化,即如果相邻间的两个批次正好可以Batch的话就会进行Batch(这么处理,可以合成一个批次,如下:)

{0 : { text   image  }}textàimage

{1 : { text  ,image }}

0: textàimage    1: textàimage

下面我们来看一个列子,这样会更加的清晰:

一个层级为0的ImageA,一个层级为1的ImageB(2个Image可Batch)和一个层级为0的TextC,

textCàimageAàimageB

一个层级为0的TextD,一个层级为1的TextE(2个Text可Batch)和一个层级为0的ImageF,

0 : textD –>imageFà1 : textEàimage h    3:

0 : textD –>imageFà1 : textEàimage h

总结:

1,有相同材质和纹理的UI元素是可以Batch的,可以Batch的UI上下叠在一块不会影响性能,但是如果不能Batch的UI元素叠在一块,就会增加Drawcall开销

2,尽量让同一个材质球上的东西 放在同一级上

3,有些情况可以考虑人为增加层级从而减少Drawcall,比如一个Text的层级为0,另一个可Batch的Text叠在一个图片A上,层级为1,那此时2个Text因为层级不同会安排2个Drawcall,但如果在第一个Text下放一个透明的图片(与图片A可Batch),那两个Text的层级就一致了,Drawcall就可以减少一个。

Text0 –》Imageàtext 1

4,应该尽量避免使用Mask,其实Mask的功能有些时候可以变通实现,比如设计一个边框,让这个边框叠在最上面,底下的UI移动时,就会被这个边框遮住;

5, z值 保持为0

UI重建:

1,动静分离:

经常发生变动的ui单独放在一个Canvase

2,删除不必要的元素。

3,CanvasRender.setDisable .

4,Text的Best Fit选项.

5,Canvas的Pixel Perfect选项

6,使用缓存池来保存ScrollView中的Item,对于移出或移进View外的的元素,不要调用disable或enable,而是把它们放到缓存池里或从缓存池中取出复用。

7, 除了rebuild过程之外,UGUI的touch处理消耗也可能会成为性能热点。因为UGUI在默认情况下会对所有可见的Graphic组件调用raycast。对于不需要接收touch事件的grahic,一定要禁用raycast。对于unity5以上的可以关闭graphic的Raycast Target而对于unity4.6,可以给不需要接收touch的UI元素加上canvasgroup组件。

 

多层级渲染:

1,canvasRender .setdisable()

2,只挂载button替代  空的image

3,不要使用空的Image,在Unity中,RayCast使用Graphi作为基本元素来检测touch,在笔者参与的项目中,很多同学使用空的image并将alpha设置为0来接收touch事件,这样会产生不必要的overdraw。通过如下类NoDrawingRayCast来接收事件可以避免不必要的overdraw。

3. public class NoDrawingRayCast : Graphic

4. {

5.     public override void SetMaterialDirty()

6.     {

7.     }

8.     public override void SetVerticesDirty()

9.     {

10.     }

11.     protected override void OnFillVBO(List vbo)

12.     {

13.         vbo.Cslear();

14.     }

}

性能检测工具:

1profile

常见问题:

Q1:我在UGUI里更改了Image的Color属性,那么Canvas是否会重建?我只想借用它的Color做Animation里的变化量。

如果修改的是Image组件上的Color属性,其原理是修改顶点色,因此是会引起网格的Rebuild的(即Canvas.BuildBatch操作,同时也会有Canvas.SendWillRenderCanvases的开销)。而通过修改顶点色来实现UI元素变色的好处在于,修改顶点色可以保证其材质不变,因此不会产生额外的Draw Call。

Q2:Unity自带的UI Shader处理颜色时,改_Color属性不会触发顶点重建吗?

在UI的默认Shader中存在一个Tint Color的变量,正常情况下,该值为常数(1,1,1),且并不会被修改。如果是用脚本访问Image的Material,并修改其上的Tint Color属性时,对UI元素产生的网格信息并没有影响,因此就不会引起网格的Rebuild。但这样做因为修改了材质,所以会增加一个Draw Call。

Q:动静分离或者多Canvas带来性能提升的理论基础是什么呢?如果静态部分不变动,整个Canvas就不刷新了?

在UGUI中,网格的更新或重建(为了尽可能合并UI部分的DrawCall)是以Canvas为单位的,且只在其中的UI元素发生变动(位置、颜色等)时才会进行。因此,将动态UI元素与静态UI元素分离后,可以将动态UI元素的变化所引起的网格更新或重建所涉及到的范围变小,从而降低一定的开销。而静态UI元素所在的Canvas则不会出现网格更新和重建的开销。

Q:UWA建议“尽可能将静态UI元素和频繁变化的动态UI元素分开,存放于不同的Panel下。同时,对于不同频率的动态元素也建议存放于不同的Panel中。”那么请问,如果把特效放在Panel里面,需要把特效拆到动态的里面吗?

通常特效是指粒子系统,而粒子系统的渲染和UI是独立的,仅能通过Render Order来改变两者的渲染顺序,而粒子系统的变化并不会引起UI部分的重建,因此特效的放置并没有特殊的要求。

Q:多人同屏的时候,人物移动会使得头顶上的名字Mesh重组,从而导致较为严重的卡顿,请问一下是否有优化的办法?

如果是用UGUI开发的,当头顶文字数量较多时,确实很容易引起性能问题,可以考虑从以下几点入手进行优化:

1.尽可能避免使用UI/Effect,特别是Outline,会使得文本的Mesh增加4倍,导致UI重建开销明显增大;

2.拆分Canvas,将屏幕中所有的头顶文字进行分组,放在不同的Canvas下,一方面可以降低更新的频率(如果分组中没有文字移动,该组就不会重建),另一方面可以减小重建时涉及到的Mesh大小(重建是以Canvas为单位进行的);

3.降低移动中的文字的更新频率,可以考虑在文字移动的距离超过一个阈值时才真正进行位移,从而可以从概率上降低Canvas更新的频率。

三、界面切换

Q1:游戏中出现UI界面重叠,该怎么处理较好?比如当前有一个全屏显示的UI界面,点其中一个按钮会再起一个全屏界面,并把第一个UI界面盖住。我现在的做法是把被覆盖的界面SetActive(False),但发现后续SetActive(True)的时候会有GC.Alloc产生。这种情况下,希望既降低Batches又降低GC Alloc的话,有什么推荐的方案吗?

可以尝试通过添加一个Layer如OutUI, 且在Camera的Culling Mask中将其取消勾选(即不渲染该Layer)。从而在UI界面切换时,直接通过修改Canvas的Layer来实现“隐藏”。但需要注意事件的屏蔽,禁用动态的UI元素等等。

这种做法的优点在于切换时基本没有开销,也不会产生多余的Draw Call,但缺点在于“隐藏时”依然还会有一定的持续开销(通常不太大),而其对应的Mesh也会始终存在于内存中(通常也不太大)。

以上的方式可供参考,而性能影响依旧是需要视具体情况而定。

Q2:通过移动位置来隐藏UI界面,会使得被隐藏的UIPanel继续执行更新(LateUpdate有持续开销),那么如果打开的界面比较多,CPU的持续开销是否就会超过一次SetActive所带来的开销?

这确实是需要注意的,通过移动的方式“隐藏”的UI界面只适用于几个切换频率最高的界面,另外,如果“隐藏”的界面持续开销较高,可以考虑只把一部分Disable,这个可能就需要具体看界面的复杂度了。一般来说在没有UI元素变化的情况下,持续的Update开销是不太明显的。

Q3:如图,我们在UI打开或者移动到某处的时候经常会观测到CPU上的冲激,经过进一步观察发现是因为Instantiate产生了大量的GC。想请问下Instantiate是否应该产生GC呢?我们能否通过资源制作上的调整来避免这样的GC呢?如下图,因为一次性产生若干MB的GC在直观感受上还是很可观的。

 

 

准确的说这些GC Alloc并不是由Instantiate直接引起的,而是因为被实例化出来的组件会进行OnEnable操作,而在OnEnable操作中产生了GC,比如以上图中的函数为例:

上图中的Text.OnEnable是在实例化一个UI界面时,UI中的文本(即Text组件)进行了OnEnable操作,其中主要是初始化文本网格的信息(每个文字所在的网格顶点,UV,顶点色等等属性),而这些信息都是储存在数组中(即堆内存中),所以文本越多,堆内存开销越大。但这是不可避免的,只能尽量减少出现次数。

因此,我们不建议通过Instantiate/Destroy来处理切换频繁的UI界面,而是通过SetActive(true/false),甚至是直接移动UI的方式,以避免反复地造成堆内存开销。

四、加载相关

Q1:UGUI的图集操作中我们有这么一个问题,加载完一张图集后,使用这个方式获取其中一张图的信息:assetBundle.Load (subFile, typeof (Sprite)) as Sprite;这样会复制出一个新贴图(图集中的子图),不知道有什么办法可以不用复制新的子图,而是直接使用图集资源 。

 

 

经过测试,这确实是Unity在4.x版本中的一个缺陷,理论上这张“新贴图(图集中的子图)”是不需要的,并不应该加载。 因此,我们建议通过以下方法来绕过该问题:

在assetBundle.Load (subFile, typeof (Sprite)) as Sprite;之后,调用

Texture2D t = assetBundle.Load (subFile, typeof (Texture2D)) as Texture2D;

Resources.UnloadAsset(t);

从而卸载这部分多余的内存。

Q2:加载UI预制的时候,如果把特效放到预制里,会导致加载非常耗时。怎么优化这个加载时间呢?

UI和特效(粒子系统)的加载开销在多数项目中都占据较高的CPU耗时。UI界面的实例化和加载耗时主要由以下几个方面构成:

纹理资源加载耗时

UI界面加载的主要耗时开销,因为在其资源加载过程中,时常伴有大量较大分辨率的Atlas纹理加载,我们在之前的Unity加载模块深度分析之纹理篇有详细讲解。对此,我们建议研发团队在美术质量允许

1,1024*768    1024*1024

2, 640*480      512*512

作者:歪歪小花鹿
链接:http://www.jianshu.com/p/5b6f5022662e
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

(转)Unity 之 UGUI 小总结的更多相关文章

  1. Unity UGUI 小知识

    1.有个控件叫Selectable 这个控件在button,slider等身上有,也可以自行添加,可通过API搜索所有带这个控件的物体统一控制. 2.实现ScrollView只使用Scrollbar操 ...

  2. Unity GUI(uGUI)使用心得与性能总结

    Unity GUI(uGUI)使用心得与性能总结 作者 kingshijie 关注 2015.09.26 15:35 字数 3686 阅读 28031评论 10喜欢 49 背景和目的 小哈接触Unit ...

  3. Unity 3D UGUI Toggle用法教程

    UGUI Toggle用法教程 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分 ...

  4. 关于 Unity 的一些小细节,不注意可能会被“坑”一些时间。

    关于 Unity 的一些小细节,不注意可能会被"坑"一些时间. 最近因为一些"小"问题,总是需要找很久的原因,总结一下 UnityEngine.Input 在使 ...

  5. 在Unity中用UGUI制作可输入下拉框

    Unity中UGUI制作可输入下拉框 目录 Unity中UGUI制作可输入下拉框 前言 组件分析 制作流程 总结 前言 在搜索引擎以及一些网页中我们常常可以看见这样一种UI控件,看上去是一个输入框,在 ...

  6. 【Unity】UGUI的Text各种小问题

    Text:用中文输入法时,无法输入汉字.输入了拼音后,按回车键无反应.目前的办法是在别的地方打好字后复制过来. Font:字体必须选一个,选None则文字变成一串黑色方块. Font Size:文字大 ...

  7. Unity引擎 UGUI

    Unity UGUI讲解 1.导入UI图片资源 2.设置参数: TextureType(纹理类型) 精灵 2D and UI SpriteMode(精灵模式)  Single(单) multiple( ...

  8. unity使用UGUI创建摇杆

    1.现在unity做一个项目,各种插件各种包,于是项目资源就无限变大了,其实一些简单的功能可以自己写,这里就是试着使用UGUI编写一个摇杆功能 2.脚本如下: using UnityEngine; u ...

  9. Unity 利用UGUI打包图集,动态加载sprite资源

    今天做了一个UI界面,这个界面是好友界面,该界面上有若干个好友item. 需要对每个tem的头像对象(image)动态显示对应的头像.尝试利用UGUI的图集来加载,具体实现如下: 1.首先,需要知道S ...

随机推荐

  1. JS和JQuery的比较

    一. Jquery它是javascript的一个轻量级框架,是对javascript进行封装. 二.JQuery和JS都有加载函数,但表达方式不同. 1.JS中的加载函数: //整个文档加载完毕后执行 ...

  2. C# File类常用方法

    File 类 提供用于创建.复制.删除.移动和打开文件的静态方法,并协助创建 FileStream 对象. 1. File.Exists ——  确定指定的文件是否存在. public static ...

  3. Delphi XE8中Delphi和JAVA数据类型对应关系!

    Delphi XE8中Delphi和JAVA数据类型对应关系所在单元文件:Androidapi.JNI.JavaTypes 对应关系: JObject = interface;//java.lang. ...

  4. git配置本地环境(phpstudy/tortoisegit/git等)

    1.下载安装phpstudy 2.下载安装git 下载地址:https://git-scm.com/downloads 3.下载安装tortoisegit,电脑64位就下载这个,如图: 4.下载安装“ ...

  5. JVM之类加载机制

    JVM之类加载机制 JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程. 类加载五部分 加载 加载是类加载过程中的一个阶段,这个阶段会在内存中生成一个代表这 ...

  6. C# Winform下一个热插拔的MIS/MRP/ERP框架(多语言方案)

    个别时候,我们需要一种多语种切换方案. 我的方案是这样的: 1.使用文本文本存储多语言元素,应用程序启动时加载到内存表中: 2.应用程序启动时从配置文件加载语种定义: 3.所有窗体继承自一个Base基 ...

  7. python 时间相关函数

    python 中与时间处理相关的模块包括 time.datetime.以及 calendar time 模块 time() 函数:time() 函数用于返回当前时间的时间戳(1970年01月08时00 ...

  8. request对象常用方法

    String getParameter(String name)根据表单组件名称获取提交数据 Sring[] getParameterValues(String name)获取表单组件对应多个值时的请 ...

  9. 修改两行代码,让nginx支持phpinfo模式

    Nginx服务器默认不支持pathinfo, 在需要pathinfo支持的程序中(如thinkphp),则无法支持”/index.php/Home/Index/index”这种网址. 网上流传的解决办 ...

  10. Qt 学习之路 2(31):贪吃蛇游戏(1)

    Qt 学习之路 2(31):贪吃蛇游戏(1) 豆子 2012年12月18日 Qt 学习之路 2 41条评论 经过前面一段时间的学习,我们已经了解到有关 Qt 相当多的知识.现在,我们将把前面所讲过的知 ...