编程文汇

unity ui 性能调优


#1

原文

  • Canvas

Canvas职责: 负责把子元素的几何体合理的批处理,并生成渲染指令,发送到Unity的图形系统。这个过程用c++实现,叫做批处理重建(rebatch)或者批处理构建(batch build)。如果Canvas包含需要rebatch的元素,可以把这个Canvas标记为Dirty。
Rebuild包含: Layout重建和Graphics重建两个步骤,也就是说如果元素的集合体变化(大小、位置)变化、以及图形、材质变化,会分别触发两个两个步骤。

  1. PreLayout
    Update data needed for layout calculations
  2. Layout
    Used by auto-layout system
  3. PostLayout
    Update data dependent on layout
  4. PreRender
    Update vertices and materials
  5. LatePreRender
    Update vertices dependent on generated text character data

Sub-Canvas: 作为Canvas子节点的Canvas称为子画板,子画板和父画板是隔离的:子画板rebatch,要求父画板同时rebatch,反之亦然。不过有部分边界情况会违反这个原则,比如修改Canvas属性。

  • batch原则:

** 两个元素(无论是否重叠),拥有有相同material和texture(同一图集),可以batch。

  • 优化方法

    • 所有UI尽量采用同一Material。

    • 减少Texuture变化,使用图集。

      • 注意:UIText文本时包含在Texture中的,可以被batch(可以观察FrameDebug看到)。(可以猜想,具有图集的TextmeshPro也一定可以batch。)
    • 切换Material的开销远远高于切换图集。切换Material时,内部渲染状态需要重建,而切换图集仅仅是增加一个drawcall,所以尽量使用相同Material。

    • 尽量不要动态修改CanvasRender属性。修改CanvasRender属性,会导致rebuild。

    • 避免修改UI对象的层次关系、兄弟节点的次序:需要重新计算深度关系,导致rebuild。

    • 避免使用PixelPerfect:每次移动Rect时都要计算自己以及子节点,把像素填充到顶点边缘,非常慢。

      • 可以静止时开启PixelPerfect,移动时关闭。
      • PixelPerfect只在WorldSpace模式有用。
    • 拆分Canvas
      Problem: 当Canvas中一个或多个元素变化后,整个Canvas标记为Dirty。需要重新分析整个Canvas:如何优化、如何batch,这个过程非常消耗cpu,很有可能降低帧数。
      Solution:拆分Canvas。每个Canvas就是一个独立的Drawcall,用的过多也会降低FPS,需要自己权衡。

      • 把静态UI和动态UI拆分到不同Canvas,
      • 把关联更新的UI放到一起
      • 也可以考虑把相同图集的元素放到一起,比如UIText:可以把所有HudText放到一个Canvas,把所有血条放到一个Canvas,避免他们因为叠加,而不能batch。
  • fq

    1. UIText重复设置相同Text的时候会触发rebuild吗?
      不会,源码为证,我们要相信unity开发人员,同样,transform设置相同pos的时候也不会。
//setter
                if (m_Text != value)
                {
                    m_Text = value;
                    SetVerticesDirty();
                    SetLayoutDirty();
                }