Chapter 4 资源优化
本章主要讲以下几种资源的优化方案
- 音频文件
- 贴图文件
- 网格和动画
- AssetBundles 和 Resources
1. 音频
1.1 音频导入设置

1.2 加载音频设置
-
Preload Audio
- 决定是否在场景初始化的时候自动加载
-
Data Load In Background
- 是否在加载时阻塞主线程(即同步加载还是异步加载)。
- 此情况下,如果没有使用
AudioClip.LoadAudioData()提前加载,可能导致播放延迟、不同步的情况。
-
Load Type
- 决定加载什么样的数据进入内存,和一次拉取多少数据。
-
Decompress On Load:
- 加载时解压并加入内存,牺牲加载时间,但播放时工作量很小。
- 这种模式一般在场景加载时加载音频,避免运行时出现卡顿。
- 适合大多数情况。
-
Compressed In Memory:
- 加载时直接拷贝文件进内存,不解压,只有播放时才解压。
- 节省加载时间和内存消耗,播放时 CPU 压力加大。
- 最适合频繁使用的大型音频文件,或者内存出现瓶颈的情况。
-
Streaming:
- 运行时加载、解码、播放。
- 内存占用最小,CPU 消耗最大。
- 适用于单一、不更换、持续性的播放,例如背景音乐和环境音效。
1.3 压缩格式和质量
| 格式 | 无损 | 大小 | 质量 | 用途 |
|---|---|---|---|---|
| PCM | YES | 大 | 好 | 极短且要求高音质的音效 |
| ADPCM | NO | 非常小 | 差 | 大量短促音效可用,例如爆炸、冲击等 |
| Compressed | NO | 小/普通 | 平台差异 | CPU 消耗高于前两种,大多数情况都可以用,可自定义质量 |
1.4 音频性能增强
-
最小化活动音源数量
- 使用音频池方式管理最大同时播放的音频数量。
-
为 3D 声音启用强制单声道
- 在立体声音文件上启用 Force to Mono,可降低 50% 空间。
-
重新采样到低频
- 需要测试效果,在可容忍的音质下选择低频采样。
-
通过混音器应用过滤效果以减少重复
- 将多个音频混音后,使用滤镜效果(Filter Effect)播放,这样可以节省磁盘空间。
- 但是每个滤镜都会消耗一定的 CPU 和内存,大量使用会造成严重的性能后果。
- 最好的办法是利用 Unity 的音频混音器,生成通用的滤镜效果模板,以最小化内存开销。官方教程:https://learn.unity.com/tutorial/audio-mixing#
-
考虑所有压缩格式
- 不要只使用默认格式。根据目标平台、音频类型和音质要求,测试不同压缩格式的效果。
-
谨慎使用 Streaming
- Streaming 虽然内存占用最小,但会引入额外的 CPU 开销和磁盘 I/O。在移动设备上要谨慎使用,避免在关键时刻产生卡顿。
-
负责任地使用远程内容流
- 从网络流式加载音频可以减少包体大小,但会引入延迟和带宽消耗。确保有合适的加载策略和错误处理。
-
考虑用于背景音乐的音频模块(Audio Module)文件
- Unity 支持的扩展名有:.it、.s3m、.xm 和 .mod,无损且内存占用小。
2. 图片纹理
2.1 纹理压缩格式
- 一般按平台和需求使用合理的压缩格式,这里给出一位朋友的具体压缩试验和策略推荐(安卓和 iOS):http://www.u3d8.com/?p=2490
- 根据 2021 年国内的调查数据,不支持 ASTC 格式的机器只有 2% 了,所以完全可以考虑移动平台双端使用 ASTC 格式。数据来源:知乎
2.2 纹理性能增强
2.2.1 减小纹理文件大小
例如手机分辨率为 1080p,就尽量少用 2048×2048 的贴图。
2.2.2 谨慎使用 Mip Map
- 注意 Generate Mip Maps 选项默认是开启的,开启后打包的纹理会比原本大 33%。
- 在纹理离摄像机距离基本固定的情况下,尽量关闭 Mip Maps。
2.2.3 从外部管理分辨率的降低
- Unity 允许直接使用 .PSD 和 .TIFF 文件。使用这些文件时 Unity 会自动生成引擎可使用的图片文件并压缩,这确实方便了美术人员,因为只需维护一个副本。
- 但是 Unity 毕竟不是专业图形软件,在生成过程中有可能产生失真。
2.2.4 调整 Anisotropic Filtering 级别(各向异性过滤)
- 这个消耗较大,谨慎使用。
2.2.5 考虑使用图集
- 使用图集可以有效降低 2D 和 UI 产生的 Draw Call,同时也可以用在一些动态合批的对象上。
- 骨骼动画(SkinnedMeshRenderer)的多个角色的纹理合在一个图集中是不能降低 Draw Call 的。
- 如果 Draw Call 不是性能瓶颈,使用图集反而会增加磁盘和内存占用,对性能不友好。
2.2.6 调整非方形纹理的压缩率
- 尽量使用正方形且为 2 的 n 次幂分辨率的纹理图片。
- 这种格式对 GPU 友好,采样效率高。
2.2.7 Sparse Textures
- Unity 提供处理超大图片的一种方式:将超大图片分割后再加载,只有摄像机看到的部分贴图进入内存。
- 这个移动端基本不使用,有兴趣的同学可以自行研究。
2.2.8 程序化材质
- 也称 Substances。
- 在初始化期间,通过自定义数学公式混合小型高质量纹理样本来生成纹理,以额外内存和 CPU 为代价,大量减少纹理带来的磁盘占用。
- 想要优化移动端包体大小的开发者可以考虑使用。
- 官方插件下载和文档
2.2.9 异步纹理上传(Asynchronous Texture Uploading)
- 这个功能 Unity 默认开启。
- 可以让纹理数据异步上传到 GPU 中,节省主线程中大量的 CPU 时间。
- 但是如果纹理开启了 Read/Write Enable,此功能无效,改为同步上传。
- 使用
Resources.Load()和LoadImage(byte[])加载的纹理无法使用此功能。
3. 网格和动画文件
3.1 减少多边形数量
- 减少多边形数量是获得性能提升最明显的方式,应该始终考虑。
- 由于 SkinnedMeshRenderer 无法使用批处理,减少其多边形数量尤为重要。
- 3D 建模/动画工具通常提供自动网格优化功能,可以估计整体形状并剥离多边形。
3.2 调整网格压缩
- 网格有 4 种压缩格式:Off、Low、Medium、High,直接影响网格数据的精度(顶点位置、法线、颜色等)。
-
Player / Other Settings 中的两个导入设置:
- Vertex Compression:可以选择想优化的数据类型,但这是个全局设置,并不好用。
- Optimize Mesh Data:把模型使用的材质球所不需要的数据在 Unity 构建时忽略掉。(如果材质球在运行中更换了,可能出现不期望的情况)
- 开启这两个属性可以减少磁盘占用,但会有额外的解压数据时间。
3.3 恰当使用 Read-Write Enable
- 开启时,内存消耗会增加,因为 Unity 会保存原始副本在内存中,关闭则不会。
- 如果网格经常在运行时以非等比缩放出现,开启是明智的。因为关闭后,每次都要重新加载网格进入内存,然后复制副本,再丢弃原始网格数据。
3.4 考虑烘培动画
- 简单、顶点数少的蒙皮动画可以烘培后再使用,一般由动画软件执行烘培过程。
- 这样可以节省空间和 CPU。
3.5 合并网格
- 一些零碎的物体,且没有相对运动,可以合并后再使用,以减少 Draw Call 和顶点数。
- Asset Store 中有不少此类插件。
4. Asset Bundles 和 Resources
Resources文件夹方便快速原型开发,但所有资源都会打包进最终构建,增加包体大小和加载时间。应尽量避免在生产环境中大量使用。AssetBundles允许将资源分离打包,按需下载和加载,是管理大型项目资源的首选方案。- 使用 AssetBundles 可以减少初始包体大小、支持热更新、按需加载资源。
- 需要注意 AssetBundle 的依赖管理、版本控制和内存释放,避免重复加载和内存泄漏。
- 更多内容可以参考 Unity 官方教程:Assets, Resources and AssetBundles。