1、UGUI简介html
UGUI是Unity官方推出的UI系统,集成了所见即所得的UI解决方案, 其功能丰富而且使用简单,同时其源代码也是开放的,下载地址:https://bitbucket.org/Unity-Technologies/ui/srcandroid
相比于NGUI,UGUI有如下几个优势:git
1. 所见即所得的编辑方式,在Scene窗口中便可编辑。github
2. 智能的Sprite packer能够将图片按tag自动生成图集而无需人工维护,生成的图集合并方式比较合理,无冗余资源。canvas
3. 渲染顺序与GameObject的Hierarchy顺序相关,靠近根节点显示在底层,而靠近叶子节点显示在顶层;这样的渲染方式使得调整UI的层级比较方便和直观。缓存
4. RectTranForm及锚点系统更适合于2D平面布局,而且很是方便多分辨率屏幕自适配。性能优化
2、UI制做规范和指导方法网络
本文是关于UGUI优化的,或许你会以为UI的制做规范及指导方法与优化无关,其实不少性能问题每每是资源的不合理使用形成的,好比使用了尺寸过大的图片、引用了过多的图集以及加载了没必要要的资源等。若是从设计和制做UI一开始就遵照特定的规范,则能够规避没必要要的性能开销。笔者根据参与的多个项目总结了如下几点通用的规范和指导方法(这些规范适用于全部项目,无论你使用UGUI仍是NGUI)。ide
1. 合理的分配图集函数
合理的分配图集能够下降drawcall和资源加载速度;具体细节以下:
● 同一个UI界面的图片尽量放到一个图集中,这样能够尽量的下降drawcall。
● 共用的图片放到一个或几共享的图集中,例如通用的弹框和按钮等;相同功能的图片放到一个图集中, 例如装备图标和英雄头像等;这样能够下降切换界面的加载速度。
● 不一样格式的图片分别放到不一样的图集中,例如透明(带Alpha)和不透明(不带Alpha)的图片,这样能够减小图片的存储空间和占用内存。(UGUI的sprite packer会自动处理这种状况)
2. resources目录中应该只保存prefab文件,其它非prefab文件(例如动画,贴图,材质等)应放到resource目录以外
由于随着项目的迭代,可能会致使部分资源(动画,贴图)等失效,若是这些文件放在resource目录下,在打包时,unity会将resource目录下文本所有打成一个大的AssetBundle包(非resouce目录下的文件只有在引用到时才会被打到包里),从而出现冗余,增长没必要要的存储空间和内存占用。能够经过如下代码(Mac环境下)在控制台窗口中查看当前目录下全部非prefab资源的代码:
find . -type f | egrep -v "(prefab|prefab\.meta|meta)$"
例如在笔者的一次扫描中,发如今了以下结果:
3. 关卡内的UI资源不要与外围系统UI资源混用
在关卡内,须要加载大量的角色及场景资源,内存比较吃紧,通常在进入关卡时,都会手动释放外围系统的资源,以便使关卡内有更多的内存可使用。若是战斗内的UI与外围系统的UI使用相同图集里的图片,则有可能会使得外围系统的图片资源释放不成功。对于关卡内与外围共用的UI资源须要特殊处理,通常来讲复制一份出来专门给关卡内使用是比较好的选择。
4. 适当的下降图片的尺寸
有时UI系统的背景可能会使用全屏大小的图片,好比在Iphone上使用1136*640大小的图片;使用这样尺寸的图片代价是很昂贵的,能够和美术同窗商量适当的下降图片的精度,使用更低尺寸的图片。
5. 在android设备上使用etc格式的图片
目前,几乎全部android设备都支持etc1格式的图片,etc1的好处是第个像素点只战用0.5个字节而普通rgba32的图片每一个像素点占4个字节,也就说一张1024*1024图片若是使用rgba32的格式所占用的内存为4M而etc1格式所占用的内存仅为0.5M。可是使用etc1格式的图片有两个限制——长和宽必须是POT的(2的N次方)而且不支持alpha通道,所以使用etc1时须要额外的一张图来存储alpha通道,而且使用特殊的shader来对alpha采样。具体的细节可参考:http://malideveloper.arm.com/resources/sample-code/etcv1-texture-compression-and-alpha-channels/
6. 删除没必要要的UI节点、动画组件及资源
随着项目的迭代,可能有部分ui节点及动画已经失效,对于失效的节点及动画必定要删除,在不少项目中,有部分同窗为了方便省事,只是将失效的节点及动画disable了。这样作虽然在运行时不会对cpu形成太多负担,可是在加载时会增长没必要要的加载时间以及内存占用。对于废弃的UI图片资源,虽然未放到Resource目录最终不会打到包里,可是在Editor模式下仍然会打到图集中从而影响优化决策。笔者写了一个扫描未使用到UI贴图资源的工具,代码地址:https://github.com/neoliang/FindUnUsedUITexture;
另外,对于废弃的脚本,可能还会有某些对象持有对它的引用,而加载这样的对象也比较耗时,笔者也写了一个扫描废弃脚本的工具,代码地址:https://github.com/neoliang/MissingScriptFinder
3、CPU优化
通常来讲,优化cpu性能应该先用profiler定位到性能热点,找到消耗最高的函数,而后再想办法下降它的消耗。通过笔者屡次使用profiler对UGUI的分析来看,其CPU性能开销高主要缘由之一是Canvs对UI网格的重建,有不少状况会触发Canvas对网格的重建,例如Image,Text等UI元素的Enable及UI元素的长、宽或Color属性的变化等。Canvas中UI Mesh顶点较多的话,则该项将会出现较高的CPU开销。在Unity的Profiler中则对应的是Canvas.SendWillRenderCanvases或Canvas.BuildBatch占用过多的时间。
Canvas.BuildBatch主要功能是合并Canvas节点下全部UI元素的网格,合并后的网格会缓存起来,只有其下面的UI元素的网格发生改变时才会从新合并。而UI元素的网络变化主要是由于Canvas.SendWillRenderCanvases调用时,rebuild了Layout或者craphic。该函数的调用过程时序图以下:
1.该过程由CanvasUpdateRegistry监听Canvas的WillRenderCanvases(上图中1)而执行,主要是对前标记为dirty的layout和craphic执行rebuild。引发layout和graphic的dirty主要缘由是由于Canvas树形结构下的UI元素发生了变化(例如增长删除UI对象,UI元素的顶点,rec尺寸改变等)调用了Graphic.SetDirty(实际上最终都会调用CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild)。
2. 在rebuild layout以前会对Layout rebuild queue中的元素依据它们在heiarchy中的层次深度进行排序(上图中的2),排列的结果是越靠近根的节点越会被优先处理。
3. rebuild layout(上图中的3),主要是执行ILayoutElement和ILayoutController接口中的方法来计算位置,Rect的大小等布局信息。
4. rebulid graphic(上图中的4),主要是调用UpdateGeometry重建网格的顶点数据(上图中5)以及调用UpdateMeterial更新CanvasRender的材质信息(上图中6)。
基于以上UGUI的网格更新原理,咱们能够作如下优化:
a. 使用尽量少的UI元素;在制做UI时,必定要仔细查检UI层级,删除不没必要要的UI元素,这样能够减小深度排序的时间(上图中的2)以及Rebuild的时间(上图中的3,4)。
b. 减小Rebuild的频率,将动态UI元素(频繁改变例如顶点、alpha、坐标和大小等的元素)与静态UI元素分离出来,放到特定的Canvas中。
c. 谨慎使用UI元素的enable与disable,由于它们会触发耗时较高的rebuild(图中的三、4),替代方案之一是enable和disableUI元素的canvasrender或者Canvas。
d. 谨慎使用Text的Best Fit选项,虽然这个选项能够动态的调整字体大小以适应UI布局而不会超框,但其代价是很高的,Unity会为用到的该元素所用到的全部字号生成图元保存在atlas里,不但增长额外的生成时间,还会使得字体对应的atlas变大。
e.谨慎使用Canvas的Pixel Perfect选项,该选项会使得ui元素在发生位置变化时,形成layout Rebuild。(好比ScrollRect滚动时,若是开启了Canvas的pixel Perfect,会使得Canvas.SendWillRenderCanvas消耗较高)
f. 使用缓存池来保存ScrollView中的Item,对于移出或移进View外的的元素,不要调用disable或enable,而是把它们放到缓存池里或从缓存池中取出复用。
g. 除了rebuild过程以外,UGUI的touch处理消耗也可能会成为性能热点。由于UGUI在默认状况下会对全部可见的Graphic组件调用raycast。对于不须要接收touch事件的grahic,必定要禁用raycast。对于unity5以上的能够关闭graphic的Raycast Target而对于unity4.6,能够给不须要接收touch的UI元素加上canvasgroup组件。
unity5.x
unity4.6
4、GPU优化
通常来讲,形成GPU性能瓶颈主要有两个缘由:复杂的vertext或pixel shader计算以及overdraw形成过多的像素填充。在默认状况下UGUI中全部UI元素使用都使用UI/Defaut shader,所以在优化时可优先考虑解决Overdraw问题。Overdraw主要是由于大量UI元素的重叠引发的,查看overdraw比较简单,在scene窗口中选择overdraw模式,场景中越亮的地方表示overdraw越高(以下图)。
为了下降overdraw,能够作以下优化:
1. 禁用不可见的UI,好比当打开一个系统时若是彻底挡住了另一个系统,则能够将被遮挡住的系统禁用。
2. 不要使用空的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<UIVertex> vbo)
12. {
13. vbo.Clear();
14. }
}
5、总结
优化UGUI性能没有万能的方法,笔者这些经验总结也只能做为参考。优化性能每每是在各类选择之间作出平衡,好比drawcall与rebuild平衡、内存打败与cpu消耗平衡以及UI图片精度与纹理大小的平衡等。每一次优化都有可能使得瓶颈出如今其它的环节上,要善于使用profiler,找到性能热点,对症下药。
6、关于资源占用问题
UI资源优化是UGUI性能优化的重点,腾讯WeTest也在资源方面提供了性能的测试。如下经过“纹理”资源,介绍腾讯WeTest性能测试在资源方面的测试状况。
一、登陆http://wetest.qq.com/cube/ ,点击“Android版 下载”,或者在页面末尾扫描二维码直接下载腾讯WeTest的手游客户端性能分析工具Cube。打开工具,选择“Unity资源分析”。
二、上传测试报告后,咱们能够经过测试报告,了解unity游戏的资源状况。
资源结论概况
进入资源数据的报告以后,首先能够看到全部资源数据的概况结果,整体上了解存在问题的数据,继续下拉,能够了解该指标的具体状况。
资源数据概况
下面将以“纹理资源”为例,对cube资源测试报告进行解读。
纹理资源
Cube测试报告的“纹理资源”,根据腾讯标准,是指望<50MB的,从下图可见,若是超出红色虚线,就说明纹理资源存在超标。
点击具体数据点,获取具体资源数据
另外,点击图表中的绿色线条中的具体数据点,能够看到这个点的当前数据,全部数据根据资源大小进行排序
全部数据根据资源大小进行排序
在这个表之下,有一个“资源大小top20”的表格,罗列了资源排名前20的资源内容。其中资源大小超过建议值的会呈现红色,资源大小非2的n次幂的呈现黄色。点击任意一个资源名称,能够在图表上观察这个资源所影响的区域:
点击具体资源了解影响区域
了解资源调用的影响区域
针对手游的性能优化,腾讯WeTest平台的Cube工具提供了基本全部相关指标的检测,为手游进行最高效和准确的测试服务,不断改善玩家的体验。目前功能还在免费开放中。
体验地址:http://wetest.qq.com/cube/
帮助中心:http://wetest.qq.com/help/documentation/10096.html
若是对使用当中有任何疑问,欢迎联系腾讯WeTest企业qq:800024531