您的位置:首页 > 移动开发 > Unity3D

Fill-rate,Canvases and input 填充率,画布和输入—(Unity3d)

2016-07-26 11:38 337 查看
版本:5.3

难易度:上级

This chapter discusses broader issues withstructuring unity UIs.

本章更广泛地讨论Unity UI结构问题

Remediatingfill-rate issues

解决填充率问题

There are two courses of action that can betaken to reduce the stress on the GPU’s fragment pipeline:

有两种方法可以减少对GPU片段的压力:

· Reducingthe complexity of fragment shaders.

减少片段着色器复杂性

o See the “UI shaders and low-spec devices” section for more details.

更多详细信息查看“UIshaders and low-spec devices”部分。

· Reducingthe number of pixels that must be sampled.

减少采样的像素数量

As the UI shader is generally standardized,the most common problem is simply excessive fill-rate usage.
This is mostcommonly due to a large number of overlapping UI elements and/or havingmultiple UI elements that occupy significant portions of the screen. Both ofthese problems can lead to extremely high levels of overdraw.

作为UI着色器通常的标准化,最常见的问题是过度的填充率使用。这是由于大量重叠的UI或则多个UI元素占用屏幕同一重要部分。这些问题都会导致严重的透支。

In order to alleviate fill-rate overutilization and reduce overdraw, consider the following possibleremediations.

为了缓解填充率过度使用,减少透支,考虑下面的方法。

Eliminating invisible UI

消除无形的UI

The method that requires the leastredesigning of existing UI elements is to simply disable elements that
are notvisible to the player. The most common case where this applicable is openingfull-screen UIs with opaque backgrounds. In this case, any UI elements placedbeneath the full-screen UI can be disabled.

减少重新设计现有UI元素的方法是简单的禁用看不见的UI元素。最常见的情况是,UI全屏打开并带有不透明的背景。这种情况下,任何在全屏下面的UI元素都是不可见的。

The simplest way to do this is to disablethe root GameObject or GameObjects containing the invisible UI
elements. For analternate solution, see the Disabling
Canvas Renderers section.

最简单的方法是禁用根目录或者包含看不见UI元素的物体。更多的解决方案,请参阅DisablingCanvas Renders 部分。

Disabling invisible camera output

禁用隐藏相机的输出

If a full-screen UI is opened in Unity UI,with an “opaque” background, the world-space camera will still
render the standard3D scene behind the UI. The renderer is not aware that the full-screen Unity UIwill obscure the entire 3D scene.

如果一个全屏UI在Unity 用户界面中打开,有一个“不透明的”背景,世界相机仍会渲染用户界面遮挡的UI。渲染器没有意识到全屏Unity用户界面会遮挡整个3D场景。

Therefore, if a completely full-screen UIis opened, disabling any and all of the obscured world-space cameras
will helpreduce GPU stress by simply eliminating the useless work of rendering the 3Dworld.

因此,如果打开了一个全屏的UI,禁用其他所有遮挡的世界相机,通过删除不必要的渲染3D世界的工作,会减少GPU压力。

Note: If a Canvas is set as “Screen
Space –Overlay”, then it will bedrawn irrespective of the number of cameras active in the scene.

注意:如果画布设置为“ScreenSpace – Overlay”,那么它将被画出,这个场景中相机激活的数量没有关系。

Majority-obscured cameras

多数-遮挡相机

Many “full-screen” UIs do not actually obscure theentire 3D world, but leave a small portion of the world
visible. In thesecases, it may be more optimal to capture just the portions of the world thatare visible into a render texture. If the visible portion of the world is “cached” in a render texture, then the actualworld-space camera can be disabled, and the
cached render texture can be drawnbehind the UI screen to provide an impostor version of the 3D world.

许多“full-screen”的用户界面不会完全遮挡整个3D世界,会留一部分可见。这种情况下,最好是捕获可见的部分到渲染纹理上。如果可见部分在渲染纹理上“缓存”了,那么实际上世界空间相机可以被禁用,缓存渲染纹理可以在UI屏幕上画出了。

Composition-based UIs

基于合成的用户界面

It is very common for designers to createUIs via composition – combining and layeringstandard backgrounds
and elements to create the final UI. While this isrelatively simple to do, and very friendly to iteration, it is nonperformantdue to UnityUI’s use of the transparent renderingqueue.

设计师通过组成-合并和分层标准的背景和元素来创建最终的UI很常见。虽然这相对很简单,而且迭代很友好,由于Unity UI使用透明渲染队列,它性能不高。

Consider a simple UI with a background, abutton and some text on the button. In the case that a pixel falls
within atext glyph, the GPU must sample the background’s texture, then the button’s texture, andfinally the text atlas’ texture, for a total of threesamples. As the complexity of the UI grows, and more decorative elements arelayered onto the background, the
number of samples can rise rapidly.

考虑一个简单的UI,一个背景图片,一个按钮,按钮上一些文字。这种情况下,像素落在字体上,GUP必须采样背景的纹理,按钮纹理,最后是字体材质,一个3个样本。对于复杂的UI,会有更多的装饰元素,样本数量也会更多。

If a large UI is discovered to be fill-ratebound, the best recourse is to create specialized UI sprites
that merge as manyof the decorative/invariant elements of the UI into its background texture .This reduces the number of elements that must be layered atop one another toachieve the desired design, but is labor-intensive and increases the size ofthe project’s
texture atlases.

如果一个大的UI被发现有填充率约束,最好的方法是创建专门的UI精灵,它们融入尽可能多的装饰/不变的UI元素。这会减少必须重叠来达到设计效果的元素数量,但是会有工作量,工程纹理帖图集(texture atlase)大小会增加。

This principle of condensing the number oflayered elements necessary to create a given UI onto specialized
UI sprites canalso be used for sub-elements. Consider a store UI with a scrolling pane ofproducts. Each product UI element has a border, a background, and some icons todenote price, name and other information.

精炼分层的UI必要的UI元素数量,创建特制的UI精灵,也可以给子元素使用。考虑一下商店界面,一个带有滚动窗口的UI,每个产品UI元素都有一个边界(border),背景,和一些代表价格、名字和其他信息的图标(icons)。

The store UI will need a background, butbecause its products scroll across the background, the product
elements cannotbe merged onto the store UI’sbackground texture. However, the border, price, name and other elements of theproduct’s UI element could be merged onto the product’s background. Depending on the size and number of icons, thefill-rate savings can
be considerable.

商店界面会需要一个背景,但是因为物品在背景上滑动,物品元素不能和背景融合。然而,边界,价格,名字和其他的物品的UI元素可以和物品背景融合。根据图标的大小和数量,填充率节省相当可观。

There are several drawbacks to combininglayered elements. Specialized elements can no longer be reused,
and requireadditional artist resources to create. The addition of large new textures maysignificantly increase the amount of memory needed to hold the UI textures,particularly if the UI textures are not loaded and unloaded on demand.

结合层元素有一些缺点。特定的元素不能再重复使用,需要重新创建素材资源。新加的大量的纹理会显著增加UI纹理的内存,特别是根据需求如果UI纹理不加载或者卸载的情况。

UI shaders and low-spec devices

UI着色器和低配置的设备

The built-in shader used by Unity UIincorporates support for masking, clipping and numerous other complexoperations.
Because of this added complexity, the UI shader performs poorlycompared to the simpler Unity 2D shader
on low-end devices such as the iPhone4.

Unity UI内置的着色器,支持遮罩(masking),裁剪(clipping),和其他复杂的操作。因为这些附加的复杂性,和Unigy 2D 着色器相比,在低端设备如Iphone4上,UI着色器的性能很低。

If masking, clipping and other “fancy” featuresare unneeded for an application targeted at low-end devices,
it is possible tocreate a custom shader that omits the unused operations, such as this minimalUI shader:

如果遮罩、裁剪和其他“花哨”的功能对于低端设备来说没有用,可以创建一个省略没有用的功能的普通着色器,如下面的UI着色器:

[C#] 纯文本查看 复制代码

?
UI Canvas rebuilds

UI画布重建

To display any UI, the UI system mustconstruct geometry for each UI component represented on-screen. This
includesrunning dynamic layout code, generating polygons to represent characters in UItext strings, and merging as much geometry as possible into single meshes inorder to minimize draw calls. This is a multi-step process and is described indetail in the Fundamentals section
at the beginning of this guide.

要显示任何UI,UI系统必须给屏幕上任意一个UI元素构建几何。这包括运行的动态布局的代码,生成多边形代表UI 文本字符串,并尽可能多的合并多边形到单个网格,这样减少draw calls。这种多步骤的过程,在Fundamentals部分详细介绍了.

Canvas rebuilds can become performanceproblems for two primary reasons:

画布重建会影响性能问题,有两个原因:

· If thenumber of drawable UI elements on a Canvas is large, then calculating the batchitself becomes
very expensive. This is because the cost of sorting andanalyzing the elements grows more-than-linearly to the number of drawable UIelements on the Canvas.

画布上可画的UI元素很多,因此计算本身的批次很昂贵。这是因为排序和分析元素比线性可画的UI元素到画布上消耗更高。

If theCanvas is dirtied frequently, then excessive time may be spent refreshing aCanvas that has relatively few changes.

如果画布经常弄脏(dirtied),大量的时间会花费在刷新相对几乎没有改变的画布。

Both of these problems tend to become acuteas the number of elements on a Canvas increases.

这两个问题都会使得画布上的元素数量增加。

Important reminder: Whenever any drawableUI element on a given Canvas
changes, the Canvas must re-run the batch buildingprocess. This process re-analyzes everydrawable UI element on the Canvas, regardless of whether it has changed or not.Note that a “change” is any change which affects a UI object’sappearance, including
the sprite assigned to a sprite renderer, transformposition & scale, the text contained in a text mesh, etc.

重要提示:当画布上可画的UI元素改变时,画布必须重新运行批次,这个过程重新分析画布上每个可画的UI元素,不管它是否改变了。注意“改变”(“change”)是任何改变UI外观,包括分配到精灵渲染器的精灵,变换位置&大小,文本网格的文本,等等。

Childorder

子类顺序

Unity UIs are constructed back-to-front,with objects’ order in the hierarchydetermining their sort order.
Objects earlier in the hierarchy are consideredbehind objects later in the hierarchy. Batches are built by walking thehierarchy top-to-bottom and collecting all objects which use the same material,the same texture and do not have intermediate layers(1).
Intermediate layers force batches to bebroken.

Unity 用户界面构建是最后面子类画在最前面,层次面板中物体的顺序决定他们排序的顺序。离层次面板越近的物体,会被挡在后面。批次由层次面板上由上到下来创建,收集所有使用同样材质的物体,同样的材质,不适用中间的层。中间层迫使批次被破坏。

As discussed in the Unity
Frame Debugger section, the frame debugger can be used to inspecta UI for intermediate layers. This is the situation where one drawable objectinterposes itself between two other drawable objects that are otherwisebatchable.

正如讨论过的Unity帧调试器部分,帧调试器可以用来监视中间层的UI。这种情况是,一个可画的物体自身插入到另外两个可画的物体间。

This problem most commonly occurs when textand sprites are located near one another: the text’s bounding
box can invisibly overlapnearby sprites, because much of a text glyph’s polygonis transparent. This can be solved in two ways:

最常见的问题是文本和精灵位置离的很近:文本边框无形地重叠在附近的精灵上,因为很多文本多边形是透明的。这可以用两种方法解决:

Reorderthe drawables so that the batchable objects are not interposed by thenon-batchable object; that
is, move the non-batchable object above or below thebatchable objects.

重新排序可画的问题,使得批量物体不会被没有批量的物体强制插入;也就是说,把非批量物体移到批量物体上面或下面。

Tweak thepositions of the objects to eliminate invisible overlapping space.

调整物体的位置,以消除不可见的重叠空间。

Both of these operations can be carried outin the Unity Editor with the Unity Frame Debugger open and enabled.
By simplyobserving the number of draw calls visible in the Unity Frame Debugger, it ispossible to find an order and position that minimizes the number of draw callswasted due to overlapping UI elements.

这两种方法都可以在Unity编辑器中使用Unity帧调试器打开和启用来实施。简单地观察Unity 帧调试器中draw calls的数量,基本上能找到一个顺序和位置来减小draw calls数量。

Splitting Canvases

拆分画布

In all but the most trivial cases, it isgenerally a good idea to split up a Canvas, either by moving elements
to a Sub-canvasor to a sibling Canvas.

在最琐碎的情况下,拆分画布通常是一个很好的方法,可以把UI元素移到子画布或同级画布上。

Sibling Canvases are best used in caseswhere certain portions of a UI must have their draw depth controlled
separatelyfrom the rest of the UI, to be always above or below other layers (e.g.tutorial arrows).

同级画布是最好的解决方法,当一部分UI必须用它们的draw深度来控制和其他的UI分离时,一直在其他层的上面或下面(如教程箭头)。

In most other cases, Subcanvases are moreconvenient as they inherit their display settings from their parent
Canvas.

大多数其他的情况,子画布更方便,因为它继承了父画布的显示设置。

While it may seem at first glance that itis a best practice to subdivide a UI into many Subcanvases, remember
that theCanvas system also does not combine batches across separate Canvases.Performant UI design requires a balance between minimizing the cost of rebuildsand minimizing wasted draw calls.

虽然咋一看,把一个UI细分成多个子画布很好,记住画布系统不会通过分离的画布结合批次。高性能的UI设计需要花费最小的重建和最小的drawcalls浪费之间的平衡。

General guidelines

一般准则

Because a Canvas rebatches any time any ofits constituent drawable components changes, it is generally
best to split anynon-trivial Canvas into at least two parts. Further, it is best to try toco-locate elements on the same Canvas if the elements are expected to changesimultaneously. An example might be a progress bar and a countdown timer. Theseboth rely on
the same underlying data and therefore will require updates at thesame time, and so they should be placed on the same Canvas.

因为一旦画布可画组件发生改变,画布就会rebatches,通常最好的方法是,将不琐碎的画布至少分为两部分。另外,最好是试一下在同一个画布上同时改变元素,如果这些元素需要同时改变。进度条和倒计时就是这样的例子。这些都依赖于相同的基础数据,因此需要同时更新,所以应该把它们放在同一个画布上。

On one Canvas, place all elements that arestatic and unchanging, such as backgrounds and labels. These
will batch once,when the Canvas is first displayed, and then will no longer need to rebatchafterwards.

在一个画布上,放置所有静态不需要改变的所有元素,如背景图片和标签。这些会在画布第一次显示时,批次一次,然后就不在重新批次了。

On the second Canvas, place all of the “dynamic”elements – the ones that change frequently. This willensure
that this Canvas is rebatching primarily dirty elements. If the numberof dynamic elements grows very large, it may be necessary to further subdividethe dynamic elements into a set of elements that are constantly changing (e.g.progress bars, timer readouts,
anything animated) and a set elements that changeonly occasionally.

在第二个画布上,放置所有动态的元素—这些需要经常改变的元素。这会确保画布重新批次主要的弄脏的(dirty)元素。如果动态元素的数量变化很大,这可能需要进一步细分这些动态元素为不断变为的元素组(如进度条,计时器读数,带动画的UI),和偶尔改变一次的元素组。

This is actually rather difficult inpractice, especially when encapsulating UI controls into prefabs. Many
UIsinstead elect to subdivide a Canvas by splitting out the costlier controls ontoa Sub-canvas.

这在实践中很困难,尤其将UI做成预制体。很多用户界面都不会选择通过拆分昂贵的控制器到子画布,这样拆分画布。

Unity 5.2 and Optimized Batching

Unity 5.2 和优化的批次

In Unity 5.2, the batching code wassubstantially rewritten, and is considerably more performant compared
to Unity4.6, 5.0 and 5.1.

unity5.2中,计算代码基本上都重写了,和Unity4.6,5.0及5.1相比,它性能会更好些。

Further, on devices with more than 1 core,the Unity UI system will move most of the processing to worker
threads. Ingeneral, Unity 5.2 reduces the need for aggressively splitting a UI into dozensof Sub-canvases. Many UIs on mobile devices can now be made performant with asfew as two or three Canvases.

另外,在带有1个以上核的设备上,UnityUI系统会将大部分处理移到工作线程上。通常,Unity5.2减少了把拆分一个UI拆分为多个字画布的需要。移动端很多用户界面可以使用两三个画布来制定高性能。

More information on the optimizations inUnity 5.2 can be found in this
blog post.

关于Unity 5.2优化的更多信息可以在这篇博客中看见。

Input and raycasting in Unity UI

Unity UI中输入和射线检测

By default, Unity UI uses the Graphic
Raycaster component to handle input events, such as touchevents and pointer-hover events. This is generally handled by the StandaloneInput Manager component. Despite the name, the Standalone Input Manager ismeant to be a “universal” input manager system,
and will handle both pointers and touches.

默认情况下,Unity UI 使用图形Raycaster组件来处理输入事件,如touch 事件和pointer-hover事件。这通常由独立的输入管理组件来处理。独立输入管理器,就是一个“通用的”输入管理系统,并会处理pointer和touch事件。

Erroneous mouse input detection on mobile(5.3)

移动端鼠标错误输入检测(5.3)

Prior to Unity 5.4, each active Canvas witha Graphic Raycaster attached will run a raycast once per frame
to check theposition of the pointer so long as there is currently no touch input available.This will occur regardless of platform; iOS and android devices
without micewill still query the mouse’sposition and attempt to discover which UI elements are beneath that position(2).

Unity 5.4之前,每个激活的画布都有一个GranphicRaycaster,会每帧检测pointer的位置,尽管目前没有可用的touch输入。这与平台无关;IOS和Android设备没有鼠标,仍会检测鼠标的位置,试图发现哪个UI元素在下方。

This is a waste of CPU time, and has beenwitnessed consuming 5% or more of a Unity application’s CPU frame
time.

这会浪费CPU时间,已经证实了,这会消耗5%或更多的Unity应用CPU帧时间。

This issue is resolved in Unity 5.4. From 5.4
onward, devices without micewill not query for the mouse position and will not perform unnecessary raycasts.

在Unity 5.4中,这个问题已经被解决。从Unity5.4开始,没有鼠标的设备将不再检测鼠标位置,并不会使用无用的射线检测。

If using a version of Unity older than 5.4,it is strongly recommended that mobile developers create their
own InputManager class. This can be as simple as copying Unity’s Standard Input Manager from the UnityUI source and commenting out the ProcessMouseEvent method as well as all callsto that method.

如果使用比Unity5.4老的版本,强烈建议移到开发人员创建自己的输入管理类。这可以简单地从Unity UI源码和注释掉的ProcessMouseEvent方法中复制Unity标准输入管理器。

Raycast optimization

射线检测优化

The Graphic Raycaster is a relativelystraightforward implementation that iterates over all Graphic components
thathave the ‘Raycast Target’ setting set to true. For each Raycast Target, the Raycasterperforms a set of tests. If a Raycast Target passes all of its tests, then itis added to the list of hits.

图形射线检测是一个相对简单的实现,遍历所有带有“Raycast Tartget”设置为true的图形组件。对于每一个设计检测的目标,射线检测执行一组测试。如果射线检测目标经过这组测试,就将它加入到点击的列表中。

Raycast implementation details

射线检测实施细节

The tests are:

测试包括:

If theRaycast Target is active, enabled and is drawn (i.e. has geometry)

如果射线检测目标是激活状态,启动并可绘制的(即有几何体的)

If theinput point lies within the RectTransform to which the Raycast Target isattached

如果输入点在RectTransform范围内。

If the RaycastTarget has, or is a child (at any depth) of, any ICanvasRaycastFilter component,
and that Raycast Filter componentpermits the Raycast.

如果RayCastTarget有一点子节点(在任何深度),任何IcanvasRayCastFilter组件,Raycast Filter组件允许射线检测。

The list of hit Raycast Targets is thensorted by depth, filtered for reversed targets, and filtered to
ensure thatelements rendered behind the camera (i.e. not visible to the screen) areremoved.

射线检测目标的列表,根据深度排序,筛选了逆向目标,过滤,确保相机后面(即屏幕看不见的)将被移除。

The Graphic Raycaster also may cast a rayinto the 3D or 2D physics system if the respective flag is set
on the GraphicRaycaster’s“Blocking Objects” property. (Fromscript, the property is named blockingObjects.)

图形检测可能会投射一个射线到3D或2D图形系统上,如果相应的标志设置了Graphic Raycaster的”Blocking Objects”属性(脚本中,属性名字是blockingObjets)。

If 2D or 3D blocking objects are enabled,then any Raycast Targets that draw beneath a 2D or 3D object on
araycast-blocking Physics Layer will also be eliminated from the list of hits.

如果2D或3D阻挡物体被启动了,那么任何在2D 或3D物体下面的在raycast-blocking 物理层的RaycastTargets也将从点击的列表中移除。

The final list of hits is then returned.

然后返回点击的最终列表。

Raycasting optimization tips

射线检测优化技巧

Given that all Raycast Targets must betested by the Graphic Raycaster, it is a best practice to only enable
the ‘Raycast Target’setting on UI components that must receive pointer events. The smaller the listof Raycast Targets, and the shallower the hierarchy that must be traversed, thefaster each Raycast test will be.

鉴于所有的射线检测目标都必须使用图形Raycster测试,最好只启动必须接收pointer 事件的UI组件的RaycastTarget。Raycast Targets列表越小,必须遍历的层级越少,射线检测测试越快。

For composite UI controls that havemultiple drawable UI objects that must respond to pointer events, such
as abutton that wishes to have its background and text both change colors, it isgenerally better to place a single Raycast Target at the root of the compositeUI control. When that single Raycast Target receives a pointer event, it canthen forward the event
to each interested component within the compositecontrol.

对于混合的UI控制,有多个可画的UI物体,需要相应pointer事件,如按钮,希望同时改变背景和文字的颜色,通常最好将单个Raycast Target放在UI控制的根目录上。当单个射线检测接收到pointer事件,它可以在复合控制中转发事件给每个感兴趣的组件。

Hierarchy depth andraycast filters

层次深度和射线检测过滤器

Each Graphic Raycast traverses theTransform hierarchy all the way to the root when searching for raycast
filters.The cost of this operation grows linearly in proportion to the depth of the hierarchy.All components found attached to each Transform in the hierarchy must be testedto see if they implement ICanvasRaycastFilter,
so this is not a cheap operation.

每个图形射线穿过变换层次直到根目录,查找射线检测过滤器。这个操作相对于层次结构的深度,成本线性增加。所有组件都必须测试,已查看它们是否实施了ICanvasRaycastFilter,所有这是一个消耗相对大的操作。

There are several standard Unity UIcomponents that make use of ICanvasRaycastFilter,
such as CanvasGroup,Image, Mask andRectMask2D,
so this traversal cannot be eliminated trivially.

有些标准的Unity UI 组件,使用了ICanvasRaycastFilter,如 CanvasGroup,Image, MaskRectMask2D,所以遍历不能被消除。

Sub-canvases and theOverrideSorting property

字画布和OverrideSorting属性

The overrideSorting property
on a Sub-canvas will cause a GraphicRaycast test to stop climbing the transform hierarchy. If it can be enabledwithout causing sorting or raycast detection issues, then it should be used todecrease the cost of raycast hierarchy traversals.

字画布上的OverrideSorting属性,会导致图形射线检测测试停止检测转换层级。如果它启动时没有导致排序和射线检测问题,那么它会降低射线检测层级遍历的花费。

Endnotes

尾注

1. An “intermediate layer” is a graphical objectwith a different material, whose bounding box overlaps
two otherwise-batchableobjects and is placed in the hierarchy between the two batchable objects.

“intermediate layer”,是一个图形物体,用了不同的材质,它的边界盒子重叠在两个batchable物体间,层级在两个batchable对象间。

2. This is to discover whether any hoverevents need to be sent.

任何hover时间需要发送时,这会被发现。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: