Unity学习—UGUI优化Tips

Unity UGUI 优化

UGUI 优化笔记

本文其他地址:简书 知乎 掘金

UI标准

UI 每帧占用时间均值2-3ms

性能问题

问题定位

  • profiling

DrawCall

  1. batch 避免同类型控件重叠
    同类型控件在不重叠时会自动合批传入一个drawcall
    UI重叠导致分层,分层导致同类型UIBatch分离,增加drawcall数量
    不规则图形,图形2D/3D旋转,图形放大,导致透明区域重叠
    z不一致也会导致分层

  2. 使用图集
    同一图集图像在合批时会自动优化到同一批,且加载时会同时加载
  3. 减少顶点修改以减少Rebatch
    如Image组件的Color属性改为修改Material属性 的tintcolor
  4. 调用方法
    Canvas.BuildBatch
    WaitingForJob
    PutGeometryJobFence
    BatchRender.Flush
  5. 单纯隐藏 UI, scale = 0, Alpha Group = 0

OverDraw

  • 关闭 Image 检测事件 一个像素位置被重复渲染

图片压缩

  • RGBA32 Bit
    • 表示每个像素占用32位4字节,内存大小 1024 X 1024 X 4 = 4M
  • RGBA16 Bit
    • 表示每个像素占用16位2字节,内存大小 1024 X 1024 X 2= 2M
  • RGB ETC1 4Bit
    • 表示每个像素占用4位0.5字节,内存大小 1024 X 1024 X 0.5= 0.5M
    • 不带透明通道
    • 图片宽和高可以不相等但是必须被4整除
  • RGBA ETC2 8Bit
    • 表示每个像素占用8位1字节,内存大小 1024 X 1024 X 1= 1M
    • 带透明通道
    • 图片宽和高可以不相等但是必须被4整除
    • OpenGL ES 3.0以上的Android手机(2013年以后)
  • RGBA PVRTC 4Bit
    • 表示每个像素占用4位0.5字节,内存大小 1024 X 1024 X 0.5= 0.5M
    • 要求图片的宽高必须相等并且是2的整数次幂,对无法满足的图片可单独打包成图集
    • 压缩的效果较差,尤其透明通道
  • RGBA ASTC 4X4
    • 表示每个像素占用8位1字节,内存大小 1024 X 1024 X 1= 1M
    • ASTC 5X5(表示每个压缩块的大小是5 X 5=25),不带透明通道
    • ASTC 4X4(表示每个压缩块的大小是4 X 4=16),带透明通道,图片宽和高可以不相等但是必须被4整除
    • ASTC只支持苹果A8以后的设备(iP6)
  • Crunched
    Unity Android 可以进行二次压缩

Android : ETC1>ETC2->RGBA16->RGBA32
iOS : PVRTC>ASTC->RGBA16->RGBA32

通道分离

针对Android平台Unity还提供了一种通道分离的方式:将图片压缩成ETC1,提取Alpha生成一张通道图。为了让混合起来的Alpha效果更好,Unity将通道图保存的格式设定为a8格式。比如一张1024X1024的贴图,ETC1压缩结果为0.5M,通道图提取后a8格式压缩结果为1M,加起来就是1.5M

通道图内存上可以减少一些,但是在Shader中需要进行2次采样

UI优化

  1. 界面中的Tab页尽量都做成单独的界面,切换后再动态加载
  2. 界面粒子特效最好不要预制在界面Prefab中,需要播放时再动态加载
  3. 界面打开从同步变成异步,从一帧变成多帧
    如打开界面先开一个底图,然后上面的元素再一个一个地冒出来,再配合一些UI动画,一帧一帧加载列表中的元素
  4. 有些类似头像或者icon的图标美术无法给出宽高被4整除的尺寸,可以给它设置一个唯一的SpriteTag打成一个图集,这样就可以压缩了
  5. 打开界面首帧Active和DeActive的次数过多,这个次数可以在Profiler中看到,其中Call的数量就是
  6. 很多UI在开发的时候都是从另一个相似界面复制一份出来,有些没用的对象只是隐藏并没有真正删除,所以要保证将没用的都删除掉
  7. 界面有可能有一些状态要进行切换,例如Tab页为了做起来方便,会把每个Tab页每个页面的内容都放进去,通过隐藏显示来控制各自的游戏对象。这种类似的情况都尽可能修改成运行时动态加载
  8. 做好分帧加载,可以将滑动列表的元素分帧一个个加载
  9. UI特效和界面上显示的模型,最好不要预制在界面中,一方面影响AssetBundle打包的依赖关系,还容易造成打开界面慢,可以通过代码动态分帧加载
  10. 尽可能少用LayoutGroup相关组件,或者自行来实现类似的功能
  11. 宽高任意一边超过256的图片最好不要打进图集
  12. 总之,对于首次打开慢的界面,我们一定要控制一帧内加载的UI元素和图集的数量
  13. 将每个界面的图片从Prefab中拆出来,将需要加载的图片名字序列化在Prefab中。这样界面中只保留了GameObject的树形结构,加载就不会慢了。界面打开后,再通过之前序列化好的名称,动态分帧地将贴图一个个加载上
  14. 操作界面之前以及操作界面之后确定UI是否在无意义重建,可以参考文章前面提到的方法得到到底哪些UI元素了引起UI的整个重建。
  15. 避免Active和DeActive,而采用修改显示layer的方式来控制隐藏显示。
  16. 不需要参与点击事件的Canvas取消激活Graphic Raycaster脚本。
  17. 仅用于显示的图片或者文本禁止勾选Raycast Target。
  18. 持续性的UI动态效果特效,最好脱离UI系统,采用特效的方式制作。
  19. 动态和静态的UI要区别对待,分别挂上canvas。
  20. 适当对UI界面做缓存,保证再次打开更快。
  21. 界面初始化代码部分添加上Profiler监测,统计代码效率。
  22. 将复杂的界面拆成多个界面,比如Tab页点击切换时再加载。
  23. 再次打开界面也需要控制一帧内加载UI的数量,做好分帧加载策略。

其他

  • 特效优化
    不要将特效放入Prefab,使用动态加载,减少AssetBundle冗余
  • 资源规划
    可使用图片的MD5进行对比,查找重复图片,合理分配图集
  • Profiler
    • Deep Profiler 查看函数栈
    • 模拟器数据不准确
    • #if UNITY_EDITOR,部分代码编辑模式下运行
    • Editor有缓存
    • 渲染性能与时间
  • List缓存池
    • 插入操作耗时,尽量Add()少Insert(),Remove可先将数据与最后一位调换再Remove,减少list整体下标移动
    • List Contain方法本质为遍历,Dictionary快很多,可单独使用Dictionary建立查询表