Unity UI 优化建议,对官方文档的理解性翻译 (一)

Unity官方原文https://learn.unity.com/tutorial/optimizing-unity-ui#5c7f8528edbc2a002053b59f

1.A guide to optimizing Unity UI

Optimizing a user interface driven by Unity UI is an art. Hard-and-fast rules are rare; instead, each situation must be carefully evaluated with the system’s behavior in mind. The core tension when optimizing any Unity UI is the balancing of draw calls with batching costs. While some common-sense techniques can be used to reduce one or the other, complex UIs must make trade-offs.

优化Unity的UI是一门艺术,很少有硬性的规则。而是需要根据系统行为进行仔细地评估。核心问题是如何

平衡DrawCalls和Batch的处理成本。虽然有一些常见的技术手段去减少一种或者另一种的处理成本,但是对于复杂的UI必须进行权衡。

However, as is best practice elsewhere, attempts to optimize Unity UIs should begin with profiling. The primary task before attempting to optimize a Unity UI system is to locate the precise reason for an observed performance problem. There are four common classes of problems encountered by users of Unity UI:

  • Excessive GPU fragment shader utilization (i.e. fill-rate overutilization)
  • Excessive CPU time spent rebuilding a Canvas batch
  • Excessive numbers of rebuilds of Canvas batches (over-dirtying)
  • Excessive CPU time spent generating vertices (usually from text)

就像优化其它方面一样,UI的优化也要先从分析开始。首要任务是定位产生明显性能问题的确切原因。大多数用户经常遇到的问题可以归为4类:

  • GPU执行了过多的片源着色器(即填充率过度使用,填充率的理解:https://blog.uwa4d.com/archives/fillrate.html
  • CPU花费了大量时间用于合批Canvas(我的理解是单一的Canvas上元素过多)
  • 合批Canvas的次数过多(我的理解是Canvas上的元素频繁变化)
  • CPU花费了大量时间生成定点(通常是文本)

It is, in principle, possible to create a Unity UI whose performance is constrained by the sheer number of draw calls being sent to the GPU. However, in practice, any project overloading the GPU with draw calls is more likely to be bound by fill-rate overutilization.

原则上,一个UI的性能受到发送给GPU的DrawCalls数量限制。但是实际运用中GPU因DrawCalls导致超负荷原因可能在于填充率的过度使用。

This guide will discuss the fundamental concepts, algorithms and code underlying Unity UI as well as discussing common problems and solutions. It is broken into five chapters:

  1. The Fundamentals of Unity UI chapter defines terminology specific to Unity UI and discusses the details of many of the fundamental processes performed to render the UI, including the building of batched geometry. It is strongly recommended that readers begin with this chapter.
  2. The Unity UI profiling tools chapter discusses gathering profiling data with the various tools available to developers.
  3. The Fill-rate, Canvases and input chapter discusses ways to improve the performance of Unity UI's Canvas and Input Components.
  4. The UI controls chapter discusses UI Text, Scroll Views and other component-specific optimizations, along with some techniques that do not fit well elsewhere.
  5. The Other techniques and tips chapter discusses a handful of issues that do not fit elsewhere, including some basic tips and workarounds for "gotchas" in the UI system.

这里就是说会分成5篇文章来讲解,继续往下看就行了。

UI Source Code

Always remember that Unity UI’s Graphic and Layout components are entirely open source. Their source code can be found on Unity’s Bitbucket repository, under UI.

Unity UI源代码

2.Fundamentals of Unity UI - 基本原理

It is important to understand the different parts making up the Unity UI system. There are several fundamental classes and components that, together, compose the system. This chapter first defines a number of terms used throughout this series of articles, then discusses the low-level behavior of several of Unity UI's key systems.

理解组成Unity UI系统的不同部分是很重要的,是由几个基本类和组件组成。本章首先定义本系列文章中使用的一些术语,然后讨论几个Unity UI系统中关键部分的底层行为。

Terminology - 术语

A Canvas is a native-code Unity component that is used by Unity’s rendering system to provide layered geometry that will be drawn in, or on top of, a game’s world-space.

Canvas是一个内置的Unity组件,Unity的渲染系统使用它来分层绘制图形,这些图形将被绘制到游戏的世界空间中,或者在世界空间最前面。

Canvases are responsible for combining their constituent geometry into batches, generating the appropriate render commands and sending these to Unity’s Graphics system. All of this is done in native C++ code, and is called a rebatch or a batch build. When a Canvas has been marked as containing geometry that requires rebatching, the Canvas is considered dirty.

Canvas负责将其组成的图形进行合批,生成适当的渲染命令,并将这些发送到Unity的图形系统。所有这些都是在内置c++代码中完成的,称为rebatch或batch build。当一个Canvas被标记为包含需要重新处理的图形时,该画布被设置为dirty(需要被绘制)。

Geometry is provided to Canvases by Canvas Renderer components.

Canvas使用Canvas Renderer组件绘制图形(所以每个Image、Text等上面都有这个组件)。

A Sub-canvas is simply a Canvas component that is nested inside another Canvas component. Sub-canvases isolate their children from their parent; a dirty child will not force a parent to rebuild its geometry, and vice versa. There are certain edge cases where this is not true, such as when changes to a parent Canvas cause a child Canvas to be resized.

Sub-canvas是指嵌套在其它Canvas里面作为自物体的Canvas。Sub-canvas使得它的子物体和父物体相互隔离;子物体上图形的变化不会导致父物体也跟着被重绘,反之亦然。但是在一些情况下也不绝对,比如父Canvas的变化导致子Canvas需要重新调整大小。

A Graphic is a base class provided by the Unity UI C# library. It is the base class for all Unity UI C# classes that provide drawable geometry to the Canvas system. Most built-in Unity UI Graphics are implemented via the MaskableGraphic subclass, which allows them to be masked via the IMaskable interface. The major subclasses of Drawable are Image and Text, which provide their eponymous components.

Graphic是由Unity UI c#库提供的一个基类。它是所有Unity UI c#类的基类,为Canvas系统提供可绘制的图形。大多数内置的Graphic都是继承于MaskableGraphic的子类,这个子类允许通过IMaskable接口来实现遮照。Drawable的主要的子类是Image和Text,它们提供了相应的组件。

Layout components control the size and positioning of RectTransforms, and are generally used to create complex layouts that require relative sizing or relative positioning of their contents. Layout components rely only on RectTransforms and only affect the properties of their associated RectTransforms. They are not dependent on the Graphic class, and can be used independently from Unity UI’s Graphic components.

Layout 组件可以控制RectTransform的大小和位置,通常用于一些布局复杂的界面,比如上面的UI元素都需要有相对大小或相对位置。Layout 组件仅依赖于RectTransforms,并且仅影响其关联的RectTransforms的属性。它们不依赖于Graphic类,可以独立于Unity UI的Graphic组件使用。

Both Graphic and Layout components rely on the CanvasUpdateRegistry class, which is not exposed in the Unity Editor's interface. This class tracks the set of Layout components and Graphic components that must be updated, and triggers updates as needed when their associated Canvas invokes the willRenderCanvases event.

The updates of Layout and Graphic components is called a rebuild. The rebuild process is discussed in further detail later in this document.

Graphic和Layout组件都依赖于CanvasUpdateRegistry类,它在Unity编辑器的接口中没有公开。该类跟踪一组必须更新的Graphic和Layout组件,并在其关联的Canvas调用willRenderCanvases 事件时根据需要触发更新。

Graphic和Layout组件的更新称为rebuild。本文后面将进一步详细讨论rebuild过程。

Rendering details - 渲染细节

When composing user interfaces in Unity UI, keep in mind that all geometry drawn by a Canvas will be drawn in the Transparent queue. That is, geometry produced by Unity UI will always be drawn back-to-front with alpha blending. The important thing to remember from a performance standpoint is that each pixel rasterized from a polygon will be sampled, even if it is wholly covered by other, opaque polygons. On mobile devices, this high level of overdraw can rapidly exceed the fill-rate capacity of the GPU.

在拼UI的时候,请记住所有由Canvas绘制的图形都将绘制在透明队列中。也就是说,由Unity UI生成的图形将总是从后向前绘制并启用alpha blend。从性能的角度来看,需要记住的重要一点是,我们绘制的图形(多边形)都将被采样,即使它完全被其他不透明的多边形覆盖。在移动设备上,这种过度的绘制很快便会超过GPU的填充率。

The Batch building process (Canvases) - Canvas合批过程

The batch building process is the process whereby a Canvas combines the meshes representing its UI elements and generates the appropriate rendering commands to send to Unity’s graphics pipeline. The results of this process are cached and reused until the Canvas is marked as dirty, which occurs whenever there is a change to one of its constituent meshes.

合批过程是这样的:一个Canvas将它下面所有UI元素的网格组合起来,并生成适当的渲染命令发送到Unity的图形管道。此过程的结果将被缓存和重用,直到这些UI元素中任一的网格发生变化时,画布会被标记为dirty。

The meshes used by the Canvas are taken from the set of Canvas Renderer components attached to the Canvas but not contained in any Sub-canvas.

Canvas所使用的网格是取自这个Canvas下的所有Canvas Renderer组件,但是不包含Sub-canvas的。

Calculating the batches requires sorting the meshes by depth and examining them for overlaps, shared materials and so on. This operation is multi-threaded, and so its performance will generally be very different across different CPU architectures, and especially between mobile SoCs (which generally have few CPU cores) and modern desktop CPUs (which often have 4 or more cores).

计算合批需要根据深度对网格进行排序,并检查重叠的部分和共享的材质球等等。这个操作是多线程的,因此它的性能在不同的CPU架构之间通常会有很大的差异,特别是在移动的SoCs(通常只有很少的CPU核心)和现代的桌面CPU(通常有4个或更多的核心)之间。

The rebuild process (Graphics) -Graphics更新(rebuild)过程

The Rebuild process is where the layout and meshes of Unity UI’s C# Graphic components are recalculated. This is performed in the CanvasUpdateRegistry class. Remember, this is a C# class and its source can be found on Unity’s Bitbucket.

Within CanvasUpdateRegistry, the method of interest is PerformUpdate. This method is invoked whenever a Canvas component invokes the WillRenderCanvases event. This event is called once per frame.

在重建过程中,Unity UI的C# Graphic组件的布局和网格被重新计算。这是在CanvasUpdateRegistry类中执行的。记住,这是一个c#类,它的源代码可以在Unity’s Bitbucket中找到。

在CanvasUpdateRegistry中,最需要注意的方法是PerformUpdate。只要画布组件调用了 WillRenderCanvases 事件,就会调用此方法。此事件每帧调用一次。

PerformUpdate runs a three-step process:

  • Dirty Layout components are requested to rebuild their layouts, via the ICanvasElement.Rebuild method.
  • Any registered Clipping components (such as Masks) are requested to cull any clipped components. This is done via ClippingRegistry.Cull.
  • Dirty Graphic components are requested to rebuild their graphical elements.

For Layout and Graphic rebuilds, the process is split into multiple parts. Layout rebuilds run in three parts (PreLayout, Layout and PostLayout) while Graphic rebuilds run in two (PreRender and LatePreRender).

PerformUpdate运行一共三个步骤:

  1. 被标记为Dirty的Layout组件请求通过 ICanvasElement.Rebuild方法重绘。
  2. 具有裁切功能的组件(例如Mask)请求去裁切那些被剪除的部分,这是通过使用ClippingRegistry.Cull方法完成的。
  3. 被标记为Dirty的Graphic组件请求重绘它们的图形元素。

对于Layout和Graphic的重绘,流程被分成多个部分。Layout重绘运行在三个部分(PreLayout、Layout和PostLayout)中,而Graphic重绘运行在两个部分(PreRender和LatePreRender)中。

Layout rebuilds - Layout重绘

To recalculate the appropriate positions (and potentially sizes) of components contained within one or more Layout components, it is necessary to apply the Layouts in their appropriate hierarchical order. Layouts closer to the root in the GameObject hierarchy can potentially alter the positions and sizes of any Layouts that may be nested within them, and so must be calculated first.

要重新计算一个或多个Layout组件中所包含的组件的适当位置(可能还有大小),需要按照适当的层次顺序应用Layout。在GameObject层次结构中(hierarchy面板所示),靠近根的Layout可能会改变嵌套其中的其它Layout的位置和大小,因此必须首先计算。(就是说Layout组件的重绘,是按照hierarchy面板所示的结构,从上向下依次计算的)

To do this, Unity UI sorts the list of dirty Layout components by their depth in the hierarchy. Items higher in the hierarchy (i.e. with fewer parent Transforms) are moved to the front of the list.

为了做到这一点,Unity UI将标记为Dirty的Layout组件按照它们在hierarchy面板中的深度来排列,越靠上的(父物体越少的)越靠前。

The sorted list of Layout components is then requested to rebuild their layouts; this is where the positions and sizes of UI elements controlled by Layout components are actually altered. For more details on how the positions of individual elements are affected by Layouts, see the UI Auto Layout section of the Unity Manual.

然后排序好的Layout组件请求重绘它们的布局;这一切发生在由Layout组件控制的UI元素的位置和大小实际发生改变的地方。有关单个元素的位置是如何受Layout影响的细节,请参阅Unity手册的UI自动布局部分。

Graphic rebuilds - Graphic重绘

When Graphic components are rebuilt, Unity UI passes control to the Rebuild method of the ICanvasElement interface. Graphic implements this and runs two different rebuild steps during the PreRender stage of the Rebuild process.

当Graphic组件被重绘时,Unity UI将控制权交给ICanvasElement接口的 Rebuild方法。Graphic实现了这个方法,并在重绘过程的PreRender阶段运行两个不同的重绘步骤。

  • If the vertex data has been marked as dirty (e.g. when the component’s RectTransform has changed size), then the mesh is rebuilt.
  • If the material data has been marked dirty (e.g. when the component’s material or texture has been changed), then the attached Canvas Renderer’s material will be updated.

Graphic Rebuilds do not proceed through the list of Graphic components in any particular order, and do not require any sorting operations.

  1. 如果顶点数据被标记为dirty(例如当组件的RectTransform改变了大小),那么网格将被重绘。
  2. 如果材质数据被标记为dirty(例如当组件的材质球或贴图被更改时),那么附加的Canvas Renderer的材质将被更新。

图形的重绘不需要任何特定的顺序去遍历Graphic组件列表,所以不需要任何排序操作。

发布了13 篇原创文章 · 获赞 1 · 访问量 436

猜你喜欢

转载自blog.csdn.net/u011366226/article/details/104548183