资源本身的优化(治本)
一、为什么这是"治本"
前面讲的AB管理、打包策略 = 管理"已有资源" = 治标 资源本身优化 = 减小"资源本体" = 治本 一张 4MB 的贴图: 再怎么优化加载/卸载策略 → 它就是 4MB 但压缩成 1MB → 直接省 75%,且所有环节都受益 ↓ 下载量↓ 内存↓ 加载速度↑ 带宽↓ GPU↑ ⚠️ 资源没优化好,后面全是补救内存占用大头排序(通常):
贴图(Texture) >> 网格(Mesh) > 音频(Audio) > 动画(Animation) ↑ 优化重点,往往占70%+内存二、贴图优化(重中之重,占内存最大头)
1. 核心认知:内存 ≠ 磁盘大小
磁盘上:hero.png = 200KB (PNG压缩) 内存中:解压成GPU格式 = 4MB! 因为GPU不能直接用PNG/JPG,必须解压成可采样格式 ↓ 内存看的是"解压后"的大小,不是磁盘文件大小2. 贴图内存计算公式
未压缩内存 = 宽 × 高 × 每像素字节数 RGBA32 (每像素4字节): 1024×1024 = 1024×1024×4 = 4 MB 2048×2048 = 2048×2048×4 = 16 MB! 开启Mipmap额外 × 1.33: 4 MB × 1.33 ≈ 5.3 MB3. 压缩格式选择(省内存关键)
各平台推荐格式:
| 平台 | 推荐格式 | 说明 |
|---|---|---|
| Android | ETC2 / ASTC | ASTC质量更好,新设备支持 |
| iOS | ASTC / PVRTC | ASTC优先,老设备PVRTC |
| PC | DXT/BC系列 | DXT5(BC3)带Alpha |
压缩效果对比(1024×1024):
┌──────────────┬─────────┬──────────┐ │ 格式 │ 内存 │ 相对RGBA32│ ├──────────────┼─────────┼──────────┤ │ RGBA32(不压缩)│ 4 MB │ 100% │ │ ASTC 6×6 │ ~0.7MB │ ~17% │ │ ETC2 │ ~1 MB │ ~25% │ │ ASTC 4×4 │ 1 MB │ 25% │ │ PVRTC 4bpp │ 0.5 MB │ ~12% │ └──────────────┴─────────┴──────────┘ 压缩后能省 75%~88% 内存!🎯ASTC 的块大小:4×4质量最高体积大,8×8体积小质量低,UI常用6×6或8×8平衡。
4. 尺寸必须2的幂次方(Power of Two)
✅ 正确:256, 512, 1024, 2048 ❌ 错误:300, 1000, 1920 原因:非2幂次方无法使用块压缩(ASTC/ETC2等) → 只能用RGBA32未压缩 → 内存暴增 例:1920×1080 非2幂 → 无法压缩 → 8MB+ 改成2048×1024(裁剪/图集) → 可压缩 → 1MB5. Mipmap 的取舍
Mipmap = 生成多级缩小版本,远处用小图(抗锯齿+性能) 内存代价:+33% 【开启】3D场景物体、远近变化的贴图 → 提升渲染质量,减少摩尔纹 【关闭】UI贴图!(UI不会缩放采样) → 省33%内存 ⚠️ UI贴图开Mipmap = 白白多占33%内存6. 其他贴图设置
Read/Write Enabled: ❌ 开启 = 内存翻倍(CPU+GPU各一份) ✅ 关闭(除非需要代码读像素) Max Size: 设置合理上限,不要用超过需要的分辨率 UI小图标 512 足够,别用 2048 Alpha通道: 不需要透明的贴图 → 去掉Alpha通道(RGB而非RGBA) → 省25%7. 图集(Sprite Atlas)—— UI优化神器
问题:100个小UI图标 = 100张贴图 → 100次DrawCall + 每张贴图内存对齐浪费 解决:合并成图集 100个小图 → 打进 1~2张大图集 ↓ DrawCall: 100 → 1~2 内存: 减少碎片和对齐浪费Unity Sprite Atlas 使用: 1. 创建 Sprite Atlas 2. 拖入要合并的Sprite 3. 设置压缩格式 4. 打包 → 运行时自动用图集三、模型/网格优化
1. 顶点数控制
内存 ≈ 顶点数 × 每顶点数据量 减少顶点: ├── 删除看不见的面(背面、内部) ├── LOD分级(远处用低模) └── 美术阶段控制建模精度 移动端参考: 角色 主角: 1w~2w面, 小怪: 3k~8k面 场景物件: 尽量低2. Read/Write Enabled(重要)
❌ 开启 = Mesh在CPU和GPU各存一份 → 内存翻倍 ✅ 关闭 = 只在GPU 例外:需要运行时修改网格/CPU读取顶点时才开 (如:程序化网格、Mesh Collider某些情况)3. 顶点数据精简
Mesh Compression:Off/Low/Medium/High 压缩顶点数据(位置/法线/UV精度) → 省内存,但可能精度损失 按需关闭不用的数据: ├── 不用光照 → 可去法线(Normals) ├── 不用切线 → 去Tangents ├── 不用第二套UV(lightmap) → 去UV2 └── 不用顶点色 → 去Colors4. 网格合并
静态物体合并: 多个静态网格 → 合并成一个 → 减少DrawCall 方式: ├── Static Batching(静态批处理) ├── Mesh.CombineMeshes └── 美术阶段合并5. LOD(Level of Detail)
根据距离切换不同精度模型: 近 ────────────────────→ 远 LOD0 LOD1 LOD2 (高模2w面) (中模5k) (低模1k) 优点:远处省顶点/DrawCall 代价:多份模型占磁盘(但内存按需)四、音频优化
1. 加载类型选择(核心)
| Load Type | 内存 | 适用 | 说明 |
|---|---|---|---|
| Decompress On Load | 高 | 短音效 | 解压到内存,播放快 |
| Compressed In Memory | 中 | 中等音频 | 压缩存内存,播放时解 |
| Streaming | 低⭐ | 长背景乐 | 边读边播,几乎不占内存 |
策略: ├── 短音效(枪声/UI点击) → Decompress On Load(快) ├── 中等(技能语音) → Compressed In Memory └── 长背景乐(BGM) → Streaming(省内存) ⚠️ 长BGM用Decompress On Load = 几MB~几十MB全进内存!2. 压缩格式
Vorbis:通用压缩,音质好,推荐大部分场景 ADPCM:轻度压缩,解压快,适合短音效 PCM:不压缩,最快最占空间(极少用) 移动端:Vorbis为主3. 采样率与声道
Sample Rate(采样率): 音效 22050Hz 通常够用(不用44100) → 省一半 Force To Mono(强制单声道): 不需要立体声的音效 → 单声道 → 省50% Quality(Vorbis质量): 拖低质量滑块,音效通常听不出差别五、动画优化
1. 压缩设置
Anim. Compression: ├── Off:不压缩(大) ├── Keyframe Reduction:删冗余关键帧(推荐) └── Optimal:Unity自动选最优 Keyframe Reduction 参数: Rotation/Position/Scale Error → 容差越大压缩越狠(但精度损失)2. 去除不必要的曲线
├── 不缩放的动画 → 移除Scale曲线 ├── Scale通常都是1 → 大量冗余可删 └── 空的/无效曲线清理3. 精度设置
Float精度: 动画曲线数值精度可降低 → 省内存,肉眼难辨六、Shader 优化
1. 变体(Variants)控制: Shader关键字组合会产生大量变体 → 编译慢+内存 → 用 shader_feature 而非 multi_compile 减少变体 → 剔除不用的变体 2. 复杂度: 移动端避免过多纹理采样、复杂运算 3. 公共Shader分离打包(前面讲过) 避免多个AB各存一份七、通用优化原则
1. 移除未使用资源
├── 定期清理项目中未引用的资源 ├── 打包时排除无用资源 └── 用工具扫描"孤儿资源" Unity: Assets → 查找未使用资源(需插件/脚本)2. 分平台优化
不同平台用不同设置(Platform Override): 贴图Inspector → 平台tab: ├── Android: ETC2/ASTC + 较小Max Size ├── iOS: ASTC └── PC: DXT + 较大尺寸 → 每个平台都用最优配置3. 资源规范(团队协作)
制定美术资源规范: ├── 贴图尺寸标准(2的幂) ├── 命名规范 ├── 面数上限 ├── 音频格式标准 └── 导入自动化设置(AssetPostprocessor)八、导入自动化(AssetPostprocessor)
// 自动设置导入参数,避免人工遗漏publicclassTextureImporter:AssetPostprocessor{voidOnPreprocessTexture(){TextureImporterimporter=assetImporterasTextureImporter;// UI贴图统一设置if(assetPath.Contains("/UI/")){importer.mipmapEnabled=false;// UI关Mipmapimporter.textureType=TextureImporterType.Sprite;}// 关闭Read/Writeimporter.isReadable=false;// 设置压缩importer.textureCompression=TextureImporterCompression.Compressed;}}💡 用 AssetPostprocessor 让资源导入时自动应用规范,杜绝人工失误。
九、优化效果检查
用 Profiler 定位大户
Profiler → Memory: ├── 按Texture排序 → 找最占内存的贴图 ├── 检查是否未压缩(RGBA32) ├── 检查UI是否开了Mipmap └── 检查是否Read/Write开启查单个资源内存
longsize=Profiler.GetRuntimeMemorySizeLong(texture);Debug.Log($"{texture.name}:{size/1024f/1024f:F2}MB");// 遍历找大贴图foreach(vartexinResources.FindObjectsOfTypeAll<Texture2D>()){longs=Profiler.GetRuntimeMemorySizeLong(tex);if(s>1024*1024)// >1MBDebug.Log($"大贴图:{tex.name}{s/1024f/1024f:F2}MB");}十、优化 Checklist
【贴图】(最重要) ☐ 用压缩格式(ASTC/ETC2),不用RGBA32 ☐ 尺寸2的幂次方 ☐ UI关闭Mipmap ☐ 关闭Read/Write(除非需要) ☐ 合理Max Size,不过大 ☐ 不透明贴图去Alpha ☐ UI用图集合并 ☐ 分平台设置 【模型】 ☐ 顶点数控制/LOD ☐ 关闭Read/Write ☐ 去除不用的顶点数据(法线/UV2/切线) ☐ Mesh Compression ☐ 静态合并 【音频】 ☐ 长BGM用Streaming ☐ 短音效Decompress On Load ☐ Vorbis压缩 ☐ 采样率22050够用 ☐ 单声道(不需立体声时) 【动画】 ☐ Keyframe Reduction压缩 ☐ 移除Scale曲线 ☐ 降低精度 【Shader】 ☐ 控制变体数量 ☐ 公共Shader分离 【工程】 ☐ AssetPostprocessor自动化导入 ☐ 清理未使用资源 ☐ 团队资源规范 ☐ Profiler定期检查核心要点
1. 资源本身优化是治本,减小本体,所有环节受益 2. 贴图是最大头(常占70%+),优化优先级最高: - 压缩格式(省75%+) ★★★ - 2的幂次方尺寸(否则无法压缩) ★★★ - UI关Mipmap(省33%) ★★ - 关Read/Write(省50%) ★★ 3. 内存看"解压后"大小,不是磁盘文件大小 4. 模型:顶点数、关R/W、去冗余数据 5. 音频:长BGM必须Streaming,短音效Decompress 6. 动画:Keyframe Reduction + 去Scale曲线 7. 分平台设置,每个平台最优配置 8. AssetPostprocessor自动化,杜绝人工遗漏 9. Profiler找大户,针对性优化