Unity UI 性能优化技术

注:本部分内容来自于我自己在《Unity3D 高级编程》阅读时做的读书总结,供学习参考;

优化技术 1:动静 UI 元素重构分离

为什么需要 UI 动静分离 Unity 中的 UGUI 和 NGUI 系统都是使用了基于网格构建的方式构建 UI 画面;在网格构建之后,都进行了网格合并的操作;

  • 不合并 UI 网格,会导致更多的 draw call,合并操作可以减少 drawcall,提升性能;
  • 问题
    • 无论当前 UI 元素是否会移动,只要当前有动态 UI 移动,就需要重构网格;
    • 一些静态的 UI 元素因为需要被合并的原因,也会被要求重构;

如何动静分离 核心点:将会移动的 UI 元素和不会动的 UI 元素分离开,减小部分 UI 元素的合并范围;

  • 重绘制合并节点
    • UGUI:Canvas
    • NGUI:UIPanel
  • 把动态的 UI 重新放置到一个新的重绘制合并节点上,静止的 UI 放在原本的节点上,实现动静网格重构分离;

优化技术 2:拆分冗余 UI

UI 元素过重 随着项目开发,一个 UI 当中被装入的东西可能会越来越多,在对 UI 进行实例化以及初始化时消耗的 CPU 也会很大,因此可以考虑将部分冗余或者过重的 UI 拆分出来;

拆分策略 核心点:把当前不需要使用的 UI 拆分成独立运作的界面,在需要展示使用的时候再调用其实例化;

  • 甚至还可以考虑把拆分出来的 UI 再进行拆分,把部分点击之后的效果作为预制体进行存储,在需要使用的时候再加载;

优化技术 3:预加载 UI

UI 元素过于琐碎 对于 UI 过于厚重的问题,可以通过拆分的方式解决;但对于大量细碎、小的 UI 元素的加载,则很难通过拆分的方式进行后加载。此时可以考虑把这部分 UI 元素的加载时间提前,使其在场景加载时就完成 UI 元素的实例化;

预加载技术 把 UI 元素的实例化和初始化提前到游戏开始之前,然后再把其隐藏;当需要使用时再显示出来;

  • 注意:预加载技术并没有减少任何 CPU 消耗,只是将 CPU 消耗的时间集中提前到了场景加载时;

优化技术 4:UI 图集的 Alpha 分离

为什么需要 Alpha 分离 UI 图集经常需要被压缩,压缩完之后可以减少 UI 的碎片化,减少 IO 读取,提升性能;但会导致画面效果变差,因为压缩时会把透明通道(Alpha)一并进行压缩。此时可以考虑单独把 Alpha 分离出来单独压缩,提升图像效果;

Alpha 分离技术

  • UGUI 的 Alpha 分离已经由 Unity 自己完成;
  • NGUI 的 Alpha 分离的原理,是将原本以 ETC 方式压缩的一张图,改为压缩一张没有 Alpha 的图和一张有 Alpha 的图;

优化技术 5:字体拆分

字体问题 项目中字体经常需要占用很大的空间,但并不是所有的字都会被经常使用;因此可以把部分 UI 所用到的常用字体拆分出来,提升 UI 性能;

如何拆分 根据场景、界面需要,从字体文件当中提取出当前场景需要的几个数字和字母,使其成为单独的字体文件;

优化技术 6:网格重构优化

Unity 网格重构机制 UGUI 只有将相同材质球的网格合并在一起,才能得到最好的效果;一个材质球对应一个图集,只有相同图集内的图片才需要合并在一起;

  • UI 元素颜色更改
    • UGUI 中,当元素需改变颜色时,需要改变当前元素的顶点颜色,然后将其重新合并到整块网格里去;
    • 因此:颜色更改需要一次性合并重构网格;
  • UI Alpha 更改
    • 和 UI 颜色一样;需要改变顶点的属性
    • 改变顶点的属性需要一次性合并重构网格;

解决方法:建立独立的特殊材质球 当不希望在 UI 颜色改变时进行网格重构,可以单独建立一个特殊的材质球;

  • 此材质球用于控制 UGUI,对这些改变颜色的 UI,使用自己的特殊材质球进行渲染;
  • 当颜色动画对颜色和 Alpha 进行更改时,只改变自定义的材质球,把渲染工作交给了新的材质球,不需要重构网格;
    • 新的材质球的颜色和 Alpha 上的变化都是通过改变材质球属性来实现的,并不是通过 UGUI 设置顶点颜色来达到效果;
    • 减少了 UGUI 重构网格的消耗;

优化技术 7:UI 展示与关闭

一般的 UI 展示与关闭 不进行优化时的 UI 元素,展示经常对应成实例化,关闭经常对应成销毁;这两个动作都很消耗性能;

  • 可以选择的策略:
    • 在关闭时选择隐藏节点而不是销毁;
    • 可以选择提前加载。打开时重新激活节点,而不进行实例化;

如何隐藏节点

  • 移出屏幕比隐藏(关闭)的效果更好
    • 移出:使 UI 元素在相机渲染之外,但仍在当前 Canvas 节点下;
    • 需要注意的是:移出后还需要关闭和此 UI 元素相关的脚本更新内容;

优化技术 8:UI 元素使用对象池

对象池运作规则 对象池就是寄存了一些废弃对象的池子。当程序需要某对象时可以向对象池申请,可以对对象池中的废弃对象再利用,在结束使用后不进行销毁,而是继续保持在对象池当中,减少实例化、销毁的动作,进行内存的重复利用;

  • UI 元素的很大一部分消耗,就是 UI 元素的重复实例化、销毁;

运用对象池的经验

  • 当程序中有重复实例化并不断销毁的对象时,可以使用对象池对其进行优化;
  • 每个需要使用对象池的对象都需要继承对象池的基类对象,这样在初始化时可以针对不同对象重载;
  • 销毁对象时使用对象池提供的回收接口,不要重复回收对象,也不要错误的放弃回收;
  • 场景结束时要及时销毁整个对象池,避免无意义的内存驻留,此时对象池已不适合新的场景了;

优化技术 9:UI 贴图设置优化

Unity 中的图片 无论导入的图片类型是 PNG 还是 JPG 类型,在 Unity 中导入并需要使用时,Unity 都会自动读取图片内容并生成一个自己格式的图片。对于这些重新生成的图片有很多内容可以进行设置并优化。

UI 贴图设置内容

  • 是否需要 Alpha 通道;
  • 是否需要进行 2 次方大小的修正;
  • 是否去除读写权限;
    • 勾选拥有读写权限的图片会使得图片所占内存大一倍;
  • 是否去除 Mipmap;
  • 选择图片压缩格式;
    • 最高的色彩度是无压缩的
    • 其次是RGBA16,色彩少了部分,且有Alpha通道
    • 再次是RBG24,没有Alpha的全彩色
    • 之后是RGB16,色彩少了一半,且无Alpha通道
    • 再后是RGBA ETC2 8位和RGBA PVRTC 4位的带Alpha通道的压缩算法
    • 最差的是 RGBA ETC 2 4 和 RGB PVRTC 4 位的不带 Alpha 通道的压缩算法

优化技术 10:内存泄漏

两种常见内存泄漏

  • 程序泄漏
    • GC 未能完整的识别需回收的垃圾而导致;
  • 资源泄漏
    • 资源使用后没有被卸载;

Mono 内存管理机制

  • Mono 介绍
    • Unity 中 CSharp 使用 Mono 作为虚拟机,因此 C Sharp 在编写一份后,可以生成中间语言后被各个平台的 Mono 单独解析,实现跨平台运行 CSharp 代码。因此 Mono 也承担了 CSharp 代码的内存管理的任务。
  • Mono 内存管理
    • Mono 有其自己堆内存,其堆内存在运行时只会增加而不会减少;
    • 每次 CSharp 向 Mono 申请内存后都会在堆内存构成的内存池当中为其进行分配,在使用结束后再归还到池当中去;
    • 当池内存不足时,会自动进行扩容;扩容时会自动进行一次垃圾回收;
    • Mono 的垃圾回收
      • Mono 中的垃圾回收会暂停哪些需要使用 Mono 进行内存分配的线程;
      • 因此主游戏线程可能会因此卡顿;

IL2CPP 内存管理机制

  • IL2CPP 介绍
    • Unity 中的 CSharp 在通过 CLR 翻译成 IL 代码后,会继续翻译成 CPP 代码;
      • 翻译生成 CPP 代码的过程由各个平台自己拥有的 CPP 编译器实现;
    • 因此 IL 2 CPP 的内存管理机制由各个平台的 VM 来进行实现;

资源泄露工具 1:MemoryProfiler 资源内存的泄漏大部分时由于加载后没有及时释放导致的;

  • MemoryProfiler 可以快照内存的信息,并将其以文件的形式进行保存和加载;

性能分析工具:Unity 自带 MemoryProfiler 可以记录各个部分的资源使用情况;

  • 检测当前场景当中不需要使用到的资源;这些资源就是泄漏的点;
  • 注意:在 Editor 下编辑场景时,Unity 编辑器本身也会加载一些资源,来使其可以在 Scene 视图中被看到,此时这些资源已经可以被 MemoryProfiler 观测,需要判断这些资源是否真的是被泄漏

寻找泄漏资源技巧:通过资源名辨识泄漏物 再给美术资源命名的时候,额可以将其所属的游戏状态放在文件名当中;

  • 比如贴图 stone.png 可以叫成 Room_stone.png

优化技术 11:针对机型性能优化

如何处理高低端机型的优化 面对不同的机型时,可以根据其性能为其评分,并按照评分得出的表现将机型分为高中低端机型;

  1. UI 贴图质量:可以对高低机型使用两套 UI 贴图,一套无压缩,无缩小,还有一套则压缩了 UI 贴图;
  2. 模型与特效区别对待:可以将模型分为多个等级,不同设备使用不同的模型等级。特效也类似,对于低端机型甚至可以删去部分非关键部位特效;
  3. 阴影:可以使用 QualitySettings 来设置不同质量的阴影,甚至不使用阴影;
  4. 贴图渲染质量:可以使用 Unity 中的 QualitySettings.masterTextureimit 的 API 来设置贴图的渲染质量;

优化技术 12:UI 图集拼接优化

优化策略 对 UI 图集优化可以减少很多浪费的空间,增加 CPU 工作效率; 几种 UI 图集优化方法:

  1. 充分利用图集空间。将图片拼在一起时,尽量减少碎片空间,比如把大图分开来拼接,大图穿插小图。
  2. 图集大小控制。如果不控制大小,容易出现 2048_2048 甚至 4096_4096 的像素的图,导致加载 UI 时异常卡顿。我们需要规范图集大小;
  3. 图片的拼接归类。在没有归类的情况下,加载 UI 会加载一些不必要的图集,导致加载速度变慢,消耗过多内存。例如可以分为常用图集(各个界面都可能用到的)、功能图集(只在某个特定界面才用到的)等。

优化技术 13:GC 优化

  1. 缓存变量;
  2. 减少逻辑调用;
  3. 清除链表;
  4. 使用对象池;
  5. 减少创建不必要的字符串、减少不必要的字符串操作;
  6. 一处游戏中的 Log 日志函数代码;
相关推荐
y先森5 小时前
CSS3中的伸缩盒模型(弹性盒子、弹性布局)之伸缩容器、伸缩项目、主轴方向、主轴换行方式、复合属性flex-flow
前端·css·css3
前端Hardy5 小时前
纯HTML&CSS实现3D旋转地球
前端·javascript·css·3d·html
susu10830189115 小时前
vue3中父div设置display flex,2个子div重叠
前端·javascript·vue.js
IT女孩儿6 小时前
CSS查缺补漏(补充上一条)
前端·css
吃杠碰小鸡7 小时前
commitlint校验git提交信息
前端
虾球xz7 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇8 小时前
HTML常用表格与标签
前端·html
疯狂的沙粒8 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员8 小时前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐8 小时前
前端图像处理(一)
前端