UGUI优化

影响性能的要素

像素填充率(FillRate)

  • 概念:指每秒每秒显卡能填充的像素数

  • 填充率和over draw息息相关,over draw由GPU影响

  • 影响像素填充率的原因

    • 半透明物体过多

      • 绘制半透明物体需要:
      • 1 开启ALPHA_BLEND
      • 2 关闭Z TEST和Z WRITE
    • 同一像素的over draw过高, 即重复绘制次数过多

  • 优化方法

    • 对于Alpha值为0,但是又要响应输入的不可见物体,采用 无绘制但能响应RayCast的组件来处理
    • 减少填充区域的覆盖,比如一个矩形区域,它的周围空白不 可见区域比较多,那可以考虑把矩形转化为若干个三角形

Draw call

  • draw call受CPU影响

  • UGUI引入了canvas的概念,提供给相同材质的 界面组件进行合批,减少draw call

  • 优化方法

    • 使用同一组材质球的UI组件,放置在同一个canvas下
    • 动静分离:canvas可以分组,如果某个界面,存在着会动 的元素和不会动的元素,则考虑分成两组。但canvas如果 先SetActive(false),再SetActive(true)。则需要ForceUpdate 它强制重绘
    • 绘制顺序不要穿插,比如A组件用了A材质球,B组件用了B材 质球,C组件用了A材质球,如果不存在相互遮盖关系的话, 那么应该在scene hierachy窗口中,将三个组件按上下顺序 排序为A,C,B

其他优化策略汇总

少用Mask组件

  • 原理:Mask组件会额外消耗多一个Drawcall来创建遮罩做像素剔除。
  • Mask组件不利于层级合并。原本同一图集里的ui可以合并层级, 仅需一个Drawcall渲染,如果加入Mask,就会将一个ui整体分割 成了Mask下的子ui与其他ui,两者只能各自进行层级合并,至少 要两个Drawcall。

字体

  • 尽量减少字体特效,outline,渐变等,可以使用本身带有描边的字体文件
  • ,尽量统一字体风格,减少不必要的额外字体文件,不用richtext

界面切换

  • 原理:增加一个新层,并且将Camera的Culling Mask中取消勾选, 即不渲染该层,UI界面在切换时,将其Canvas所在Layer设置为该 层,看起来就像被隐藏了
  • 优点:于切换时基本没有开销,也不会产生多余的 Draw Call
  • 缺点:隐藏时依然还会有一定的持续开销,而其对应的Mesh 也会始终存在于内存中。

各种界面隐藏方案的优劣分析

  • SetActive产生GC,会导致画布丢弃它的VBO数据,从而重建和重新批处理,操作频繁时GC导致CPU占用可能会卡顿。
  • enable Canvas禁用画布,能降低dc,避免SetActive的GC开销,但测试依旧会有SendWillRenderCanvases函数的调用开销。
  • 移出RootCanvas,似乎没有多大优化,理论上会降低dc且不会引起重建。
  • 将单独界面使用Canvas,绑定一个Camera在隐藏时设置Layer进行CullingMask蔽,同时禁用GraphicsRaycaster,能避免重建,但随着canvas增多dc会增多,同时界面较时管理比较费力,注意动态UI的事件。
  • 设置Canvas Group 的alpha为0:依旧会被渲染,但能避免setactive带来的巨大开销,且容易操作。
  • 更改Scale的值为0:点信息被清除,这样不会减少dc开销,同时还会引起重建,不采用。
  • 设置一个Canvas作为根节点,将其layer设置为相机屏蔽的层级,同时禁用GraphicsRaycaster,当需要隐藏某个界面时将其以该Canvas作为根节点移到其下,这样能避免重建同时减少dc,但会有一些SetParent带来的消耗。目前采用该方案。
  • 如果只是隐藏某个Graphic类的,可以考虑获取canvasRenderer.cull 设置为true (需要注意的是,在使用 RectMask2D时,该属性会被修改,一般可在非使用RectMask2D的时候代码处理)