【Unity 性能优化之路——概述(0)】
Unity性能优化概述
性能优化不是某个环节的极致压榨,而是所有模块的协同共进。本文将为你建立完整的Unity性能优化知识体系。
很多Unity开发者一提到性能优化,首先想到的就是Draw Call、Batches这些渲染指标。这没错,但它们只是性能优化中的一部分。真正的性能优化是一场全方位的战役,涉及CPU、GPU、内存、资源管理和代码质量等方方面面。
性能优化的核心:木桶理论
一个游戏的性能表现,如同一个木桶的容量,不取决于最长的那块木板,而取决于最短的那块。我们可以将渲染优化到极致(Batches极少),但一段糟糕的脚本或一个内存泄漏就足以让游戏卡顿甚至崩溃。
全局性能优化检查清单
为了帮助你系统地进行优化,可以遵循下图的全局性能优化检查流程来定位和解决问题:
下面,我们粗过流程中提到的各个模快优化点。
一、CPU性能优化
CPU是游戏的大脑,负责处理逻辑、物理和渲染指令。CPU瓶颈通常表现为Profiler中CPU主线程出现高峰。
1. 脚本优化
- 优化Update逻辑,将不必要的计算移出Update或降低其执行频率:避免在
Update
、FixedUpdate
、LateUpdate
中执行繁重操作(如查找对象、计算复杂算法)。 - 缓存引用:使用
GetComponent
、Find
等方法获取的引用,应在Start
或Awake
中缓存,避免每帧查询。 - 协程与异步:合理使用
Coroutine
和异步操作(async/await
)处理延时任务,避免阻塞主线程。
2. 物理优化
- 简化碰撞体:坚决不使用
MeshCollider
,多用BoxCollider
、CapsuleCollider
等原始碰撞体组合。 - 减少刚体:仅为需要物理引擎驱动的对象添加
Rigidbody
。静态物体设为Static
。 - 调整频率:通过修改
Time.fixedDeltaTime
提高物理更新间隔,非物理游戏不必保持0.02s。 - 优化碰撞层:在Physics Settings中设置层碰撞矩阵,禁用不必要的层间碰撞。
3. UI优化
- 减少Canvas重建:UI元素的变化(位置、颜色、文本)会触发Canvas重建。将频繁变化的UI元素放在独立的Canvas上。
- 禁用Raycast Target:对于不需要点击事件的Image/Text,取消勾选
Raycast Target
,减少不必要的射线检测。 - 对象池化列表:对滚动列表使用对象池(如Unity的
ScrollRect
循环列表),避免频繁实例化/销毁。
4. 动画优化
- 简化Animator:避免使用过于复杂的Animator Controller,减少状态和过渡的数量。
- 使用动画裁剪:对不可见的角色(如远处的NPC),通过
Animator.cullingMode
停止其动画更新。
二、GPU性能优化
当CPU很空闲但帧率依然不高时,瓶颈就在GPU。
1. 渲染优化
- 降低Batches:这是核心目标。通过静态合批、GPU Instancing、SRP Batcher等技术,减少Draw Call。
- 降低SetPass Calls:减少材质种类。使用纹理图集(Sprite Atlas) 让多个物体共享同一材质。
- 使用LOD:为复杂模型配置LOD Group,根据距离相机远近显示不同精度的模型。
- 启用遮挡剔除:使用Occlusion Culling,避免渲染被遮挡的物体。
2. 填充率与Overdraw
- 控制分辨率:对于移动设备,适当降低渲染分辨率是最直接的优化方式。
- 简化后处理:屏幕后处理效果(如Bloom、SSAO)非常消耗性能,务必谨慎使用。
- 警惕透明物体:半透明物体叠加会导致像素被多次绘制(Overdraw)。应尽量减少透明区域的面积。
3. 着色器与光照
- 选择移动端Shader:为移动平台使用轻量级的Shader(如
Universal Render Pipeline/Simple Lit
)。 - 优化光照:减少实时光源的数量,多用烘焙光照(Baked Lightmap)。
- 简化粒子特效:控制粒子系统的最大粒子数、发射频率和重叠程度。
三、内存与资源优化
内存问题不会直接导致帧率下降,但会引发卡顿(GC)和崩溃,尤其影响移动设备。
1. 资源管理
- 纹理优化:使用压缩格式(ASTC),尺寸设为2的幂次方,关闭不必要的
Read/Write
选项。 - 音频优化:使用压缩格式(Vorbis),将
Load Type
设置为Compressed In Memory
,避免WAV文件。 - 模型优化:在建模软件中减少面数,导出时开启压缩选项。
2. 资产生命周期管理
- 使用对象池:对于频繁创建和销毁的对象(子弹、敌人、特效),使用Object Pooling模式复用。
- 管理AssetBundle:动态加载和卸载资源包,及时调用
Resources.UnloadUnusedAssets
。 - 避免内存泄漏:注意静态变量、事件监听等对对象的引用,防止其无法被GC回收。
3. 代码质量与GC
- 避免GC分配:杜绝在Update中
new
对象、使用字符串连接(如Debug.Log
)、Lambda表达式等。多用结构体(Struct)和缓存。 - 使用值类型:对于小型、短暂的数据,使用
Struct
而非Class
,因为它们分配在栈上,不会触发GC。
总结:性能优化的方法
- 不要猜测,要 profiling:Unity Profiler是最强大、最权威的工具。任何优化决策都应基于Profiler的数据。
- 确立目标:不同平台(PC、移动端、VR)的性能标准天差地别。先明确你的目标帧率和设备。
- 迭代优化:优化是一个“分析 -> 修改 -> 验证”的循环过程,而非一蹴而就。
- 全局思维:时刻记住木桶理论,确保CPU、GPU、内存三大核心均衡发展,没有明显短板。