一、项目总览
Unity 性能优化初级篇(一):项目总览与优化基线
本文整理自视频:《Unity 性能优化》系列课程第零节——项目创建与总览。本文聚焦如何快速认识一个陌生 Unity 项目,以及如何在优化开始前建立可重复、可比较的性能基线。
文中的性能、内存与包体数字均为视频示例项目的优化前观测值,只用于记录该案例的初始状态,不代表 Unity 移动端项目的通用性能预算。
一、为什么优化前必须建立基线
性能优化不是简单地修改参数、降低画质或删除资源,而是一个不断提出问题、收集证据和验证结果的过程。
如果没有优化前基线,即使修改后帧率发生变化,也很难回答下面这些问题:
- 性能是否真的有所改善?
- 改善来自 CPU、GPU,还是测试场景发生了变化?
- 帧率提高后,内存、画质和包体是否变差?
- Android 和 iOS 是否获得了相同收益?
- 当前修改解决的是主要瓶颈,还是无关紧要的局部问题?
因此,在开始优化前,应当记录至少四类信息:
| 维度 | 需要关注的内容 |
|---|---|
| 性能 | 帧率、CPU 帧耗时、GPU 帧耗时、卡顿峰值 |
| 渲染 | 三角形数、Batch、SetPass Call、实时灯光、阴影 |
| 内存 | 总内存、纹理、网格、音频、Shader 等资源占用 |
| 交付 | 安装包大小、画面异常、声音异常、平台差异 |
这些数据共同构成项目的初始状态。后续每完成一轮优化,都应在相同条件下重新测试,并与初始状态比较。
二、快速盘点陌生项目
接手一个陌生项目时,不应立即进入某个场景修改参数。首先需要知道项目中“有什么”,再判断哪些内容值得深入检查。
Unity Project 窗口支持使用 Search by Type 按资源类型搜索。例如,可以通过 t: 过滤器快速查找指定类型的资源:
| 搜索条件 | 资源类型 | 主要关注点 |
|---|---|---|
| t:Model | 模型 | 数量、面数、骨骼、是否存在重复资源 |
| t:Material | 材质 | 材质数量、Shader 类型、实例化情况 |
| t:Texture | 纹理 | 分辨率、格式、压缩方式、Mip Map |
| t:AudioClip | 音频 | 时长、压缩格式、加载方式 |
| t:Shader | Shader | 自定义 Shader 数量、变体规模 |
| t:Script | 脚本 | 运行时系统、管理器、更新逻辑 |
资源数量本身不能直接证明存在性能问题,但可以帮助我们建立第一印象:
- 大量高分辨率纹理可能带来显存和包体压力;
- 大量材质可能增加渲染状态切换;
- 复杂模型可能推高顶点处理成本;
- 音频资源可能同时影响内存和安装包大小;
- 较多自定义 Shader 需要进一步检查复杂度与变体数量。
这一阶段的目标不是立即下结论,而是找出值得进一步测量的方向。
三、检查场景复杂度
完成资源盘点后,需要进入主要场景,检查真正参与运行和渲染的对象。
摄像机
首先确认场景中有多少台启用的摄像机,以及它们各自负责什么:
- 是否存在额外的 UI、反射或特效摄像机?
- 是否使用 Camera Stack?
- 不同摄像机是否重复渲染相同对象?
- 摄像机是否启用了不必要的后处理、深度纹理或颜色纹理?
额外摄像机可能意味着额外的剔除、渲染和后处理开销。不能只看 Hierarchy 中有多少个 Camera,还要确认实际启用状态、Culling Mask 和渲染目标。
灯光与阴影
实时灯光和实时阴影通常是移动端项目的重要成本来源。检查时应关注:
- 实时灯光的数量和类型;
- 灯光影响范围是否过大;
- 是否有多个实时灯光同时影响同一区域;
- 哪些灯光开启了阴影;
- 阴影距离、分辨率和级联设置;
- 项目使用前向渲染还是延迟渲染。
视频示例场景只有一台摄像机,但实时灯光数量较多,因此灯光与阴影被列为后续重点分析方向。
灯光数量不能单独决定最终性能。实际成本还与渲染路径、屏幕覆盖率、阴影设置、材质和目标硬件有关,最终仍需通过真机 Profiler 验证。
场景资源规模
随后观察场景内模型、粒子、植被、地形和透明物体的规模:
- 可见模型是否具有较高面数?
- 远处物体是否仍使用高精度模型?
- 是否存在大量透明或半透明对象?
- 粒子系统是否具有较大的屏幕覆盖率?
- 地形、植被和建筑是否同时产生较高渲染成本?
- 是否有本应静态的对象持续参与动态计算?
这一步的作用是建立场景结构与性能指标之间的对应关系,为后续分析提供上下文。
四、检查平台与渲染管线配置
同一个 Unity 项目在不同平台、Quality Level 和渲染路径下,表现可能完全不同。
Quality Level
需要确认编辑器和目标设备实际使用的 Quality Level,而不是只查看某一档配置。
不同质量等级可能使用不同的:
- 渲染管线资源;
- Render Scale;
- 阴影距离和阴影分辨率;
- 抗锯齿方式;
- 纹理质量;
- 各向异性过滤;
- 垂直同步策略。
如果测试设备使用的质量等级不同,采集到的数据便失去直接可比性。
Rendering Path
确认项目当前使用前向渲染还是延迟渲染。
不同路径对灯光、带宽、Render Target、Shader 和移动 GPU 的影响不同。不能仅凭“某一种渲染路径通常更快”就直接调整,而应结合场景灯光结构、目标设备和 Profiler 数据判断。
视频案例将延迟渲染可能带来的带宽和显存压力列为重点关注方向,但这只是待验证假设,不是已经证实的瓶颈结论。
Render Feature 与管线功能
如果项目使用 URP,还应检查 Renderer 中启用的 Render Feature,以及是否生成了额外中间纹理。
重点关注:
- 自定义 Render Feature;
- Camera Color Texture;
- Depth Texture;
- Opaque Texture;
- 后处理;
- 屏幕空间效果;
- 额外的 Blit 或全屏 Pass。
这些功能可能是画面效果的必要组成部分,也可能引入额外 Render Pass、显存和带宽开销。检查的目的不是全部关闭,而是确认每项功能是否真的被项目使用。
五、采集编辑器渲染基线
Game 视图的 Stats 面板可以快速展示当前帧的一部分渲染统计信息,适合作为初步筛查工具。
视频示例项目中观察到的编辑器数据如下:
| 指标 | 视频案例观测值 |
|---|---|
| 平均三角形数 | 约 150 万~200 万 |
| 峰值三角形数 | 约 230 万 |
| Batch | 约 1500~1800 |
| SetPass Call | 超过 200 |
上述数字只用于记录该示例项目的优化前状态,不代表 Unity 移动端项目的通用预算或合格标准。
三角形数
三角形数反映当前视野内提交给渲染管线的几何规模,但不能脱离设备和场景单独评价。除了数量,还要考虑:
- 顶点属性数量;
- Shader 顶点阶段复杂度;
- 蒙皮和变形计算;
- 重复渲染;
- 深度和阴影 Pass;
- 移动 GPU 的实际处理能力。
Batch
Batch 可以帮助判断一帧中提交了多少批渲染工作,但它不等同于 Draw Call,也不能作为唯一优化目标。
批次数较高时,可以进一步检查材质是否过度拆分、动态对象是否破坏合批、GPU Instancing 是否适用、SRP Batcher 是否正常工作,以及阴影和额外 Pass 是否产生了重复绘制。
SetPass Call
SetPass Call 可以近似反映渲染状态和 Shader Pass 切换情况。大量材质、不同 Shader、不同关键字组合以及多 Pass 渲染,都可能增加该指标。
减少 SetPass Call 不能只靠合并模型,还需要从材质复用、Shader 设计、渲染功能和资源组织方式上综合分析。
编辑器数据的局限
编辑器 Stats 适合快速发现异常,但不能替代真机测试:
- 编辑器本身存在额外开销;
- PC GPU 与移动 GPU 的架构不同;
- 编辑器分辨率通常与设备分辨率不同;
- 移动端还会受到功耗、温度和系统调度影响;
- 不同图形 API 的驱动行为可能不同。
因此,Stats 只是基线的一部分,最终判断必须来自目标设备。
六、建立可重复的真机测试环境
为了让优化前后的结果能够比较,测试条件必须尽量保持一致。
构建与 Profiler
调试构建时可以启用 Development Build 和 Autoconnect Profiler,方便通过 Unity Profiler 观察:
- CPU Usage;
- GPU Usage;
- Rendering;
- Memory;
- Audio;
- Physics;
- UI。
Development Build 会引入额外开销,因此适合定位问题,不适合直接代表最终发布版本的绝对性能。需要评估正式性能时,应补充非 Development Build 的发布配置测试。
分析时不应只盯着 FPS。帧率只是最终结果,真正需要定位的是每帧时间消耗在哪里,以及峰值由什么事件触发。
Debug View
项目或渲染管线提供的调试视图可以辅助检查材质属性、光照复杂度、Overdraw、阴影、Render Pass、中间纹理和渲染异常。
如果某个平台出现过曝、颜色错误或其他画面差异,调试视图可以帮助区分问题来自资源、材质、光照、色彩空间还是渲染管线。
保持测试条件一致
每轮测试至少应固定以下条件:
- 相同设备和系统版本;
- 相同构建配置;
- 相同 Quality Level;
- 相同分辨率和渲染比例;
- 相同场景、摄像机位置和运行路径;
- 相同帧率限制与垂直同步设置;
- 尽量接近的设备温度和电量状态;
- 相同采样时长。
视频案例为了观察真实性能关闭了垂直同步。实际项目中还应确认是否存在 Application.targetFrameRate 等其他帧率限制,避免将主动限帧误判为性能不足。
七、示例项目的真机基线
视频分别在小米 11 Ultra 和 iPhone XS Max 上测试了示例项目。
以下数据均为视频案例观测值,不是移动端项目的推荐预算,也不能直接套用到其他项目或设备。
| 项目 | 小米 11 Ultra | iPhone XS Max |
|---|---|---|
| 帧率 | 十几 FPS | 十几 FPS,但案例中相对更高 |
| 内存 | 约 1.5 GB | 约 1 GB |
| CPU/GPU | 存在 GPU 端渲染性能瓶颈,CPU 耗时也不乐观;仍需用 Profiler 定量定位 | 存在 GPU 端渲染性能瓶颈,CPU 耗时也不乐观;仍需用 Profiler 定量定位 |
| 画面异常 | 地形出现过曝 | 部分贴图颜色异常 |
| 音频异常 | 视频未强调明显异常 | 无声音 |
| 安装包 | Android APK 约 500 MB | 视频未给出可直接比较的包体数据 |
这些数据说明,该项目在优化前同时存在多类问题:
- 两台设备的帧率均较低;
- 两台设备均存在 GPU 端渲染性能瓶颈,CPU 耗时也不乐观;
- 运行内存较高;
- Android 安装包较大;
- 不同平台存在不同的渲染异常;
- iOS 端还存在声音异常;
- 编辑器中的渲染统计指标较高。
尤其需要注意:iPhone XS Max 在视频案例中的帧率相对更高,不代表该设备一定比小米 11 Ultra 更适合运行这个项目。两台设备的分辨率、图形 API、渲染路径、驱动、质量等级和运行状态都可能不同,在控制变量之前不能直接比较硬件性能。
八、形成待验证的优化假设
完成盘点和基线采集后,可以形成问题清单,但此时仍不能把猜测写成结论。
渲染路径是否适合目标设备
待验证问题:
- 当前 Rendering Path 是否符合场景灯光结构?
- 延迟渲染产生的 G-Buffer 是否带来了较高带宽和内存压力?
- 切换渲染路径后,灯光、Shader 和画面效果是否仍然正确?
验证时应保持场景和设备不变,分别测试不同渲染路径,并比较 GPU 帧耗时、内存、带宽相关表现和画面差异。
分辨率是否影响设备间差异
待验证问题:
- 两台设备的实际渲染分辨率是否一致?
- Render Scale 是否一致?
- 是否启用了动态分辨率?
- UI 和后处理是否按照完整屏幕分辨率执行?
如果分辨率不同,GPU 像素处理量也会不同。只有统一测试条件后,才能判断分辨率是不是帧率差异的主要原因。
实时灯光与阴影是否构成主要瓶颈
待验证问题:
- 同屏实时灯光数量是否过多?
- 阴影是否覆盖了过大范围?
- 是否存在不必要的投射阴影对象?
- 当前渲染路径是否放大了灯光成本?
可以逐项禁用灯光和阴影进行对照测试,但必须记录每次修改对画面的影响。
资源体量是否导致内存和包体过高
待验证问题:
- 内存主要由纹理、网格、音频还是其他资源占用?
- 是否有资源在运行时被重复加载?
- 是否存在远高于实际需求的纹理分辨率?
- 音频是否使用了不合适的加载方式?
- 构建中是否包含未使用或重复资源?
需要结合 Memory Profiler、构建报告和资源引用关系继续分析,不能仅凭 Project 窗口中的文件数量下结论。
跨平台异常是否来自配置或资源兼容性
Android 地形过曝、iOS 贴图颜色异常和无声音是不同类型的问题,需要分别定位:
- 过曝是否与灯光、曝光、色彩空间、HDR 或后处理有关?
- 贴图颜色异常是否与纹理格式、色彩空间、Shader 或平台压缩有关?
- 无声音是否与音频格式、导入设置、运行时逻辑或平台权限有关?
这些现象可能与性能问题同时出现,但不一定由同一个原因造成。优化过程中必须保留画面和功能正确性验证。
九、Unity 项目接手检查清单
下面的检查清单可以作为陌生 Unity 项目的首次性能摸底流程。
项目与资源
场景与渲染
编辑器基线
真机基线
问题整理
总结
性能优化的第一步不是修改,而是测量。
接手陌生 Unity 项目时,应先完成资源盘点和场景检查,再确认平台、质量等级、渲染路径及管线功能。随后通过编辑器 Stats 建立初步印象,并在目标设备上使用 Profiler 采集真实的 CPU、GPU、内存和渲染数据。
视频案例中的高三角形数、高 Batch、较多 SetPass Call、十几 FPS、较高内存和跨平台异常,共同构成了该项目的优化前基线。这些现象可以帮助提出优化假设,但不能代替验证。
后续每一项优化都应遵循同一套闭环:
发现现象 → 提出假设 → 控制变量 → 真机测量 → 对比基线 → 验证画质与功能只有能够被稳定复现和量化比较的改进,才是真正有效的性能优化。
