优化Unity UI的技巧

1. 使用更多画布

画布组件的主要任务是管理在层次窗口中绘制UI元素的网格,并在发出渲染这些元素所需的Draw Call。画布的另一个重要作用是将网格合并进行批处理(条件是这些网格的材质相同),以降低 Draw Call 数。然而,当画布或其子对象发生变动时,这称为“画布污染”。当画布污染后,就需要为画布上的所有UI对象重新生成网格,才可发出 Draw Call。这个重新生成网格的过程不是一个简单的任务,也是Unity项目中性能问题的常见来源,遗憾的是,很多因素都会导致画布污染。即使更改画布上的单个UI元素也会导致这种情况的发生。有很多因素会导致画布污染,只有很少因素不会(通常在指定状态下),所以最好还是谨慎行事,并假定任何变化都会导致这种后果。

提示:

唯一值得注意的是,更改U元素的颜色属性不会污染画布。

2. 在静态和动态画布中分离对象

应该努力尝试在生成画布时,采用基于元素更新的时间给元素分组的方式。元素可分为3组:静态、偶尔动态、连续动态。静态UI元素永远不会改变,典型的示例有背景图像、标签等。动态元素可以更改,偶尔动态对象只在做出响应时更改,例如UI按钮按下或暂停动作,而连续动态对象会定期更新,例如动画元素。

应该根据UI指定的部分,尝试将这3个组中的UI元素拆分到3个不同的画布,这将最大限度地减少重新生成元素期间浪费的工作量。

3. 为无交互的元素禁用Raycast Target

UI元素具有Raycast Target选项,允许该元素通过单击、触摸和其他用户行为进行交互。当以上任何一个动作发生时,GraphicsRaycaster 组件将执行像素到边界框检查,以确定与之交互的是哪个元素,这是一个简单的迭代for 循环。对非交互元素禁用此选项,就减少了GraphicsRaycaster需要迭代的元素数量,提高了性能。

4. 通过禁用父画布组件来隐藏UI元素

UI使用单独的布局系统来处理某些元素类型的重新生成工作,其操作方式类似于污染画布。UIlmage、UIText和 LayoutGroup都是属于这个系统的组件示例。很多操作可能导致布局系统被污染,其中最明显的是启用和禁用这些元素。但是,如果想禁用UI的一部分,只要禁用其子节点的画布组件,就可以避免布局系统的这种昂贵的重新生成调用。为此,可以将画布组件的enabled属性设置为 false。这种方法的缺点是,如果任何子对象具有Update()、FixedUpdate()、LateUpdate()或 Coroutine()方法,就需要手动禁用它们,否则这些方法将继续运行。禁用画布组件,只会停止UI的渲染和交互,各种更新调用应继续正常执行。

5. 避免Animator组件

Unity 的Animator组件从未打算用于最新版本的UI系统,它们之间的交互是不切实际的。每一帧,Animator都会改变UI元素的属性,导致布局被污染,重新生成许多内部UI信息。应该完全避免使用Animator,而使用自己的动画内插方法或使用可实现此类操作的程序。

6. 为World Space画布显式定义 Event Camera

画布可用于2D和3D中的UI交互,这取决于画布的 Render Mode设置是配置为Screen Space (2D)还是World Space (3D)。每次进行UI交互时,画布组件都会检查其eventCamera属性(在 Inspector窗口中显示为Event Camera)以确定要使用的相机。默认情况下,2D画布会将此属性设置为Main Camera,但3D画布会将其设置为null。遗憾的是,每次需要 Event Camera时,都是通过调用FindObjectWithTag()方法来使用Main Camera。通过标记查找对象并不像使用Find()方法的其他变体那样糟糕,但是其性能成本与在给定项目中使用的标记数量呈线性关系。更糟的是,在 World Space画布的给定帧期间,Event Camera 的访问频率相当高,这意味着将此属性设置为null,将导致巨大的性能损失而没有真正的好处。因此,对于所有的World Space画布,应该将该属性手动设置为Main Camera。

7. 不要使用alpha 隐藏UI元素

color 属性中 alpha值为О的UI元素仍会发出 Draw Call。应该更改UI元素的isActive 属性,以便在必要时隐藏它。另一种方法是通过CanvasGroup组件使用画布组,该组件可用于控制其下所有子元素的alpha透明度。画布组的 alpha值设置为0,将清除其子对象,因此不会发出任何 Draw Call。

8. 优化 ScrollRect

ScrollRect组件是一种UI元素,用来在列表中滚动其他UI元素,这在移动应用中相当常见。遗憾的是,这些元素的性能随着大小的改变会变得非常差,因为画布需要定期重新生成它们。但是,可以用很多方式改善ScrollRect组件的性能。

使用 RectMask2D

只要把其他UI元素的depth值设置为低于ScrollRect元素,就可以实现滚动式UI特性。但这并不是一种好的实现方案,因为ScrollRect中的元素不会被剔除,当ScrollRect移动时,需要为每帧重新生成每个元素。如果元素未被剔除,就应使用RectMask2D组件来裁剪和剔除不可见的子对象。此组件创建了一个空间区域,如果其中的任何子UI元素超出了RectMask2D组件的边界,就会被剔除。相对于渲染太多不可见对象的成本,剔除对象所付出的成本一般更划算。
优化Unity UI的技巧_第1张图片

在ScrollRect中禁用Pixel Perfect

Pixel Perfect是画布组件上的一个设置,它强制其子UI元素与屏幕上的像素对齐。这通常是美术和设计的一个要求,因为UI元素将比禁用它时显示得更加清晰。虽然这种对齐操作是相当昂贵的,但它是强制性的,可以保证大部分的UI元素显示得更清晰。但是,对于动画和快速移动的物体,由于涉及运动,因此Pixel Perfect没多大意义。禁用ScrollRect元素的Pixel Perfect属性是一种节省大量成本的好方法。但是,由于Pixel Perfect设置会影响整个画布,因此为画布下的子对象启用ScrollRect,以便其他元素与其像素对齐。

手动停用ScrollRect活动

即使移动速度是每帧只移动像素的一小部分,画布也需要重新生成整个ScrollRect元素。一旦使用ScrollRect.velocity和ScrollRect.StopMovement()方法检测到帧的移动速度低于某个阈值,就可以手动冻结它的运动。这有助于大大降低重新生成的频率。

9. 查看文档

前面的提示是UI系统中比较晦涩、未公开或关键的性能优化技巧。Unity网站上有大量的资源来解释UI系统的工作原理和优化方案。通过以下页面,可以了解更多有用的UI优化技巧,网址为:https://unity3d.com/learn/tutorials/temas/best-practices/guide-optimizing-unity-ui

摘取:
Unity 游戏优化(第2版) 作者:[英] 克里斯·迪金森

你可能感兴趣的:(Unity优化,ui,unity)