参考文章:
UWA问答:关于UI重建的一些问题
UWA厚积薄发:关于Unity中的UGUI优化,你可能遇到这些问题
WeTest:如何快速优化手游性能问题?从UGUI优化说起
这篇的目的是记清楚UGUI中网格更新和重建(合并)两个概念。
1、网格更新(对应Canvas.SendWillRenderCanvases)
更新指的是UI元素本身的某些属性发生变化,从而需要重新生成,或者更新顶点属性。
总的来说,“网格更新”更新的是顶点属性。
这里的顶点属性,指的是UIVertex结构的成员,也就是下面几个变量,其中常用的只有position和color两个。清楚这一点,要分辩哪些操作会引发更新就容易了。
Variables | Desc |
---|---|
UIVertex.color | Vertex color. |
UIVertex.normal | Normal. |
UIVertex.position | Vertex position. |
UIVertex.tangent | Tangent. |
UIVertex.uv0 | UV0. |
UIVertex.uv1 | UV1. |
在UGUI中颜色的变化是通过修改顶点色实现的
修改Image、Text的color属性,会改变UIVertex.color;修改RectTransform的Size、Anchors、Pivot等,会改变UIVertex.position,所以这些操作都会引发网格更新。
直观感觉上,修改RectTransform(Transform)的Position、Rotation和Scale会改变顶点的position。但测试下来,这些操作不会带来更新的开销,也不会改变顶点position。根据打印出来的数据看,UIVertex.position记录的是本地空间下的坐标,因此存储值不会受到Transform属性的影响。
SendWillRenderCanvases
1)Graphic.Rebuild()
- UpdateGemotry()
- 改变RectTransform的Size
- UpdateMaterial()
- 修改Color
2)LayoutRebuilder.Rebuild()
2、网格重建/合并(对应Canvas.BuildBatch)
在 UGUI 中,Batch是以Canvas为单位的,即在同一个Canvas下的UI元素最终都会被Batch到同一个Mesh中。而在Batch前,UGUI会根据这些UI元素的材质(通常就是Atlas)以及渲染顺序进行重排,在不改变渲染结果的前提下,尽可能将相同材质的UI元素合并在同一个SubMesh中,从而把DrawCall降到最低。而Batch的操作只会在UI元素发生变化时才进行,且合成的Mesh越大,操作的耗时也就越大。
Unity的文档把这个问题说的更加明确。
Important reminder: Whenever any drawable UI element on a given Canvas changes, the Canvas must re-run the batch building process. This process re-analyzes every drawable 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’s appearance, including the sprite assigned to a sprite renderer, transform position & scale, the text contained in a text mesh, etc.
重要提示:当给定Canvas上的任何可绘制UI元素发生更改时,Canvas必须重新执行合批过程。此过程重新分析Canvas上的每个可绘制UI元素,不管它是否被修改。注意,“更改”是指影响UI元素外观的任何变动,包括修改sprite renderer的sprite、transform的position和scale、文本网格的text等。
综上,只要UI元素变了,就会引发网格重建(BuildBatch);只有当元素的顶点属性发生变化,才会出现网格更新(SendWillRenderCanvases)。重建出现的频率应该是高于更新的,因为更新总是伴随着重建。
根据我不太靠谱的测试,更新的开销普遍高于重建,可能是由于重建在Native中执。