zoukankan      html  css  js  c++  java
  • ui优化

    https://mp.weixin.qq.com/s/mLd5INIVhkBQvbbXVLmDzw

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

    划分画布

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

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

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

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

    解决方案:划分画布

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

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

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

    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画布上,因为这样做无法检查交互事件。

    避免使用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属性。

    避免使用布局分组

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

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

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

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

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

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

    巧妙地聚集UI对象

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

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

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

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

    如何隐藏画布

    问题:如何隐藏画布?

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

    解决方案:禁用Canvas组件。

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

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

    UI元素上Animator的最佳用法

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

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

    解决方案:

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

    小结

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

  • 相关阅读:
    django 项目需要注意的一些点
    VUE之路
    Oracle 表格碎片的查看方法
    RHEL 6.x or 7.x 使用分区绑定ASM 磁盘的方法
    RMAN 修复主库 nologging 操作导致物理备库的坏块
    Oracle 数据库19c 回退降级到 11.2.0.4 方案
    如何评估oracle 数据库rman全备和增量备份大小
    在将Oracle GI和DB升级到19c或降级到以前的版本之前需要应用的补丁 (Doc ID 2668071.1)
    Oracle 数据库坏块处理
    opatch auto 安装11.2.0.4.20190115 PSU遇到 OUI-67133: Execution of PRE script failed,with returen value 1 报错
  • 原文地址:https://www.cnblogs.com/nafio/p/9732986.html
Copyright © 2011-2022 走看看