UWA

每天一点UWA:UI优化小结

Posted by 蔡华的博客 on September 10, 2017

说明

  • 经过一个半月的学习,对UI的优化有了一些心得,同时也希望把零散的知识点总结到一起,因此有了这个专题。

那些需要关注的性能指标函数

UGUI参考的函数

  • 1、Canvas.SendWillRenderCanvases() 该API为UI元素自身发生变化(比如被Enable或者被缩放,移动并不算)时所产生的调用。发生在canvas被渲染之前。

  • 2、Canvas.BuildBatch 该API为UI元素合并的Mesh需要改变时所产生的调用。通常之前所提到的Canvas.SendWillRenderCanvases()的调用都会引起Canvas.BuildBatch的调用。另外,Canvas中的UI元素发生移动也会引起Canvas.BuildBatch的调用。

NGUI参考的函数

  • UICamera.Update() 该函数通常在点击时出现开销。因此,当该函数的CPU开销较高时,通常都是因为调用了其他的较为耗时的函数引起。

  • UIRect.Update() 该函数通常在需要更新锚点位置时出现开销。因此,当该函数的CPU开销持续较高时,通常是因为当前场景中有较多的UI元素绑定了OnUpdate模式的锚点。

  • UIPanel.LateUpdate() 该函数为NGUI最主要的CPU开销,包含了对所有UI界面包括其下UI元素的状态更新、网格重建、DrawCall合并等操作。大量的UI变动或者不合理的UIPanel布局都有可能导致该函数出现较高的峰值。

  • UIRect.Start() 该函数主要涉及到UI元素的初始化操作,通常在UI界面被实例化时出现并产生一定的CPU开销。

一些需要知道的UI原理

mesh合并

  • 一个Canvas下的所有UI元素都是合在一个Mesh中的。
  • 而在Batch前,UGUI会根据这些UI元素的材质(通常就是Atlas)以及渲染顺序进行重排,在不改变渲染结果的前提下,尽可能将相同材质的UI元素合并在同一个SubMesh中。所以同一Canvas下不同的材质的UI可能会合并为多个SubMesh。

UI重建

  • 关于UI重建的说明。UI其实是一些3D的quad,这一下就能够理解为什么存在UI的减少少drawcall了,这个和模型的减dc完全一个原理。

  • 在UGUI中,网格的更新或重建(为了尽可能合并UI部分的DrawCall)是以Canvas为单位的,且只在其中的UI元素发生变动(位置、颜色等)时才会进行。因此,将动态UI元素与静态UI元素分离后,可以将动态UI元素的变化所引起的网格更新或重建所涉及到的范围变小,从而降低一定的开销。而静态UI元素所在的Canvas则不会出现网格更新和重建的开销。
  • 在这再次对更新和重建进行一些详细的说明:

    更新指的是UI元素本身的某些属性发生变化,从而需要重新生成,或者更新顶点属性。比如颜色变了,在UGUI中颜色的变化是通过修改顶点色实现的,所以就需要更新UI元素对应的每个顶点的顶点色属性(可以认为就是修改下某个数组里的数值)。位置移动一般是不会造成顶点属性的变化的。所以总的来说,“网格更新”更新的是顶点属性。

    UI元素和别的网格不同点在于,UI的网格是需要进行合并的,并且在UGUI中是以Canvas为单位的,在提交GPU之前,同一Canvas下的所有UI元素都会被合入一个Mesh中(但包含多个SubMesh)。所以位置的移动,顶点属性的变化,都会导致这个Mesh要重新合并,也就是网格重建。这也是为什么说要“动静分离”的原因,完全静态的Canvas是不需要重建的,但只要里面有一个UI元素在动,就会引起Canvas的重建。

    在UGUI里更改了Image的Color属性,其原理是修改顶点色,因此是会引起网格的Rebuild的(即Canvas.BuildBatch操作,同时也会有Canvas.SendWillRenderCanvases的开销)。通过修改顶点色来实现UI元素变色的好处在于,修改顶点色可以保证其材质不变,因此不会产生额外的Draw Call。

    Unity自带的UI Shader处理颜色时,改 _Color属性不会触发顶点重建吗?

    在UI的默认Shader中存在一个Tint Color的变量,正常情况下,该值为常数(1,1,1),且并不会被修改。如果是用脚本访问Image的Material,并修改其上的Tint Color属性时,对UI元素产生的网格信息并没有影响,因此就不会引起网格的Rebuild。但这样做因为修改了材质,所以会增加一个Draw Call。

    综上所述,移动不一定会更新,但是会重建。而颜色变化或者大小变化带来的都是重建。

优化建议:

  • 动静分离,动的频率不同也分离,减少Mask组件的使用,使用Mask不仅会增加GPU端渲染的压力,同时也会造成CPU端DrawCall的明显上升。可尝试用RectMask2D来进行替换。
  • 减少OnEnable和OnDisable,通过移动位置、改变摄像机culling mask。后者可能会一定程度地提高内存的开销(UIDrawCall中存储的Mesh)
  • 修改material改颜色和直接改color属性在性能消耗要权衡。一个加drawcall一个会重建,要根据测试结果来。