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 日志函数代码;
相关推荐
古蓬莱掌管玉米的神4 小时前
vue3语法watch与watchEffect
前端·javascript
林涧泣4 小时前
【Uniapp-Vue3】uni-icons的安装和使用
前端·vue.js·uni-app
雾恋4 小时前
AI导航工具我开源了利用node爬取了几百条数据
前端·开源·github
拉一次撑死狗4 小时前
Vue基础(2)
前端·javascript·vue.js
祯民4 小时前
两年工作之余,我在清华大学出版社出版了一本 AI 应用书籍
前端·aigc
热情仔5 小时前
mock可视化&生成前端代码
前端
m0_748246355 小时前
SpringBoot返回文件让前端下载的几种方式
前端·spring boot·后端
wjs04065 小时前
用css实现一个类似于elementUI中Loading组件有缺口的加载圆环
前端·css·elementui·css实现loading圆环
爱趣五科技5 小时前
无界云剪音频教程:提升视频质感
前端·音视频
计算机-秋大田5 小时前
基于微信小程序的校园失物招领系统设计与实现(LW+源码+讲解)
java·前端·后端·微信小程序·小程序·课程设计