本文将介绍一些提升Unity UI性能的技巧。更多优化技巧,可以观看Unity工程师Ian Dundore在Unite Europe 2017的演讲《使用Unity性能提升技巧》。

1.划分画布

问题:UI Canvas上有一个或多个元素变化时,会污染整个画布。

画布(Canvas)是Unity UI的基本组件。它会生成网格来呈现放置在画布上的UI元素,当UI元素变化时,它会重新生成网格并向GPU发起绘图调用,从而显示出UI。

生成这些网格会消耗大量性能,需要将UI元素收集到批处理中,从而尽可能减少绘图调用。因为批处理的生成过程性能消耗较大,通常只在必要时候才重新生成。问题在于,当画布上有一个或多个元素变化时,必须重新分析整块画布,才能得到绘制元素的最优方法。

许多用户将整个游戏的UI都放到一块画布,上面摆放了成百上千个元素。因此当修改其中一个元素时,会产生持续数毫秒的CPU使用量飙升情况。

解决方案:划分画布

每块画布上的元素都与其它画布的元素相隔离,所以我们可以使用工具来切分画布,从而解决Unity UI的批处理问题。

我们也可以通过嵌套画布来解决,这样允许设计师创建大型分层UI,而且不必担心不同内容出现在多个画布上。子画布的内容与父画布和同级画布相互隔离,它们会保持自带几何体,执行自己的批处理。

当使用子画布分离画布时,尝试根据画布更新时间来分组。例如:分离动态元素和静态元素。

2.Graphic Raycaster的最佳用法

问题:Graphic Raycaster有哪些最佳用法?

Graphic Raycaster组件能够将输入内容转换为UI事件,它会把触屏输入转为事件,然后发送给相关UI元素。每个接收输入内容的画布都需要Graphic Raycaster组件,包括子画布。

尽管该组件名为Graphic Raycaster,但它却不是个光线投射器,默认情况下它只会测试UI图形。该组件会获取特定画布上输入信息相关的UI元素集,然后执行交点测试,它会针对Graphic Raycaster的画布上每个交互式UI元素的RectTransform,检查输入事件发生的位置。

解决方案:关闭静态或非交互式元素的Raycast Target。

例如:有一个带文字的按钮,关闭该元素的Raycast Target会直接减少Graphic Raycaster每帧进行的交点测试次数。

问题:有时候Graphic Raycaster会充当光线投射器使用。

如果将画布上的渲染模式设为世界空间摄像机(Worldspace Camera)或屏幕空间摄像机(Screen Space Camera),此时可以设置阻挡遮罩(Blocking Mask)。

阻挡遮罩决定光线投射器是通过2D物理还是3D物理投射光线,从而了解特定物理对象是否阻挡用户与UI交互。

解决方案:通过2D或3D物理投射光线会消耗不少性能,所以要谨慎使用该功能。

尽量减少Graphic Raycaster的数量,不要将Graphic Raycaster添加到非交互式UI画布上,因为这样做无法检查交互事件。

3.避免使用Camera.main

问题:世界空间画布需要了解交互事件来自哪个摄像机。

当设置画布进行渲染时,不管该画布是在世界空间还是摄像机的屏幕空间,都可以指定用于为UI中Graphic Raycaster生成交互事件的摄像机。渲染模式为“Screen Space - Camera”的画布需要使用该设置,该设置名为“Render Camera”。

然而在渲染模式为“World Space”的画布上,该设置是可选的,名为“Event Camera”。

如果将世界空间画布的Event Camera字段留空,这不意味着该画布不会接收事件。它会使用游戏的主摄像机。为了确定哪个摄像机是主摄像机,该画布会访问Camera.main属性。

根据Unity所使用的代码路径,每帧中每有一个Graphic Raycaster和世界空间画布,该画布会访问7到10次Camera.main。每次访问Camera.main都会调用Object.FindObjectWithTag。这个做法在运行时并不合适。

解决方案:避免使用Camera.main

缓存摄像机的引用,然后创建系统来跟踪主摄像机。如果使用世界空间画布,要指定Event Camera,不要将该属性留空。如果需要修改Event Camera,编写代码来更新Event Camera属性。

4.避免使用布局分组

问题:每个影响布局的UI元素都会至少执行一次GetComponents调用。

当修改布局系统的一个或多个子元素时,会使布局变脏。修改后的子元素会使拥有该元素的布局系统(Layout System)无效化。

简单介绍一下布局系统:布局系统是一组连续的布局分组(Layout Group),它们在布局元素(Layout Element)之上。布局元素不只是名为Layout Element的组件,它们还包括UI图像、文字和Scroll Rect组件,而且Scroll Rect同时也是布局分组。

回到问题本身,每个使布局变脏的UI元素都会至少执行一次GetComponents调用,该调用会在布局元素父对象上寻找有效的布局分组。找到有效布局分组后,它会继续遍历Transform层级,直到停止寻找分组或是到达层级的根部分,无论先满足哪个条件都会停止寻找过程。因此。每个布局分组会给每个子布局元素的改变过程添加一次GetComponents调用,使嵌套布局分组的性能变差。

解决方案:避免使用布局分组。

使用锚点进行比例布局。在拥有动态元素数量的活跃UI上,考虑编写代码来计算布局,仅在需要时运行该代码,而不是每次发生改变的时候。

5.巧妙地聚集UI对象

问题:用错误的方法聚集UI对象。

通常情况下,用户通过重置父对象来聚集UI对象,然后再禁用对象,但这样会造成不必要的污染。

解决方案:首先禁用对象,然后将其父对象重置为对象池。

这样操作仅会改变一次原有的层级,但在重置父对象时,要避免二次改变原有的父对象,也不要改变新的层级。如果要从对象池移除对象,首先重置它的父对象,然后更新数据,再启用该对象。

6.如何隐藏画布

问题:如何隐藏画布?

有时需要隐藏UI元素和画布,要怎样高效完成该任务呢?

解决方案:禁用Canvas组件。

禁用Canvas组件会阻止画布向GPU发起绘图调用,所以该画布不再可见。然而,此时该画布不会丢弃它的顶点缓冲区,它会保留所有网格和顶点,当重新启用时不会触发重构过程,它只会重新绘制画布内容。

此外,禁用Canvas组件不会触发Canvas层级上性能消耗较大的OnDisable/OnEnable回调。禁用子组件时要小心,注意它是否运行性能消耗较大的每帧代码。

7.UI元素上Animator的最佳用法

问题:如何在UI上使用Animator?

Animator每帧都会改变元素,即使动画中的数值没有变化。Animator没有空指令检查。

解决方案:

只在频繁变化的动态元素上加入Animator。对于很少变化的元素,或是仅响应事件时才变化的元素,请自行编写代码或补间系统,你可以在Asset Store资源商店找到许多补间系统插件。

小结

提升Unity UI性能的技巧就为大家分享到这里,更多关于Unity的优化技巧请访问Unity官方中文论坛(UnityChina.cn) !

文章来源于unity微信公众号:Unity官方平台

原文链接:  Unity UI性能优化技巧

Unity UI性能优化技巧的更多相关文章

  1. Android UI性能优化详解

    设计师,开发人员,需求研究和测试都会影响到一个app最后的UI展示,所有人都很乐于去建议app应该怎么去展示UI.UI也是app和用户打交道的部分,直接对用户形成品牌意识,需要仔细的设计.无论你的ap ...

  2. JavaScript 如何工作:渲染引擎和性能优化技巧

    翻译自:How JavaScript works: the rendering engine and tips to optimize its performance 这是探索 JavaScript ...

  3. Java程序性能优化技巧

    Java程序性能优化技巧 多线程.集合.网络编程.内存优化.缓冲..spring.设计模式.软件工程.编程思想 1.生成对象时,合理分配空间和大小new ArrayList(100); 2.优化for ...

  4. Python代码性能优化技巧

    摘要:代码优化能够让程序运行更快,可以提高程序的执行效率等,对于一名软件开发人员来说,如何优化代码,从哪里入手进行优化?这些都是他们十分关心的问题.本文着重讲了如何优化Python代码,看完一定会让你 ...

  5. Python 代码性能优化技巧(转)

    原文:Python 代码性能优化技巧 Python 代码优化常见技巧 代码优化能够让程序运行更快,它是在不改变程序运行结果的情况下使得程序的运行效率更高,根据 80/20 原则,实现程序的重构.优化. ...

  6. Python 代码性能优化技巧

    选择了脚本语言就要忍受其速度,这句话在某种程度上说明了 python 作为脚本的一个不足之处,那就是执行效率和性能不够理想,特别是在 performance 较差的机器上,因此有必要进行一定的代码优化 ...

  7. Unity 绘图性能优化 - Draw Call Batching

    Unity 绘图性能优化 - Draw Call Batching Unity官方链接:http://docs.unity3d.com/Manual/DrawCallBatching.html 转载请 ...

  8. JavaScript 性能优化技巧分享

    JavaScript 作为当前最为常见的直译式脚本语言,已经广泛应用于 Web 应用开发中.为了提高Web应用的性能,从 JavaScript 的性能优化方向入手,会是一个很好的选择. 本文从加载.上 ...

  9. MySQL 性能优化技巧

    原文地址:MySQL 性能优化技巧 博客地址:http://www.extlight.com 一.背景 最近公司项目添加新功能,上线后发现有些功能的列表查询时间很久.原因是新功能用到旧功能的接口,而这 ...

随机推荐

  1. quartz一次简单应用经历

    项目里使用到每月的第一天需要定时统计上一个月的某种数据,这个时候,我开始第一次知道任务调度这么一个专业词汇.也初次了解quartz这个任务调度框架.网上看了好几篇博文,有种quartz越看越难的感觉, ...

  2. 继承中的prototype与_proto_

    继承的核心是原型链,它的基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法. 例:SubType.prototype = new SuperType (); var instance = ...

  3. C语言学习书单

    1.C Primer Plus(第六版)(中文版)豆瓣详情 ​ C Primer Plus 最大的缺点可能就是内容太细,对于C语言讲解极为细致,但对于Sequence Point等内容并没有详细讲解. ...

  4. 安装php rabbitmq扩展,继上一篇安装Rabbitmq

    1 安装 rabbitmq-c,C 与 RabbitMQ 通信需要依赖这个库,这里只贴出正确的步骤,错误类型太多,不一一举例,大部分都是安装问题,缺少组件,安装目录问题 git clone git:/ ...

  5. JUnit学习笔记-0-JUnit启动类

    [说明]:本文基于JUnit4.13版本代码,JDK1.8.0_151环境,使用工具为Eclipse,版本为Oxygen.1a Release (4.7.1a) [图示]: [正文]:JUnit4.1 ...

  6. jenkins as code 与go语言学习

    前言 最近看jenkins as code这个概念在很多文章中提起,持续交付中八大原则也有把一切都放入版本管理,最近准备把我们公司用的一些jenkins上的job的配置也放到git中,由于https: ...

  7. ACM计划

    原文 :http://027xbc.blog.163.com/blog/static/128159658201141371343475/ ACM主要是考算法的,主要时间是花在思考算法上,不是花在写程序 ...

  8. 初识Dubbo+Zookeeprt搭建SOA项目

    由于工作中天天和Dubbo打交道,天天写对外服务,所以有必要自己动手搭建一个Dubbo+zookeeper项目来更更深层次的认识Dubbo 首先了解一下SOA: 英文名称(Service Orient ...

  9. Python小练习之判断一个日期是一年的第几天

    python练手遇到的一个问题写了个统一公式,不用麻烦的分各种类,如果有人测试出错误请评论通知. #分单双月 def dayNum(month,day,isLeap): if month % 2 != ...

  10. 使用Sybmol模块来构建神经网络

    符号编程 在之前的文章,我们介绍了NDArray模块,它是MXNet中处理数据的核心模块,我们可以使用NDArray完成非常丰富的数学运算.实际上,我们完全可以使用NDArray来定义神经网络,这种方 ...