3. 资源压缩基础:纹理压缩(ETC2/ASTC)、音频压缩(Vorbis/Opus)、模型LOD与网格压缩

资源压缩,说白了就是给游戏资源「减肥」。我见过太多项目,美术资源动辄几百兆,结果在低端机上直接闪退。你想想看,一张 2048×2048 的 RGBA 纹理,不压缩就是 16MB,一个场景贴几十张,内存直接爆炸。

这一章我们聚焦三个核心方向:纹理、音频、模型。每个方向我都会给出实战中验证过的方案和参数。

核心原则:压缩不是无脑压到最小,而是在「视觉/听觉可接受」的前提下,把带宽和内存压到最低。

3.1 纹理压缩:ETC2 与 ASTC

纹理压缩是资源减肥的大头。移动端目前主流就两个格式:ETC2 和 ASTC。

3.1.1 ETC2:Android 的底线

ETC2 是 OpenGL ES 3.0 的强制要求。换句话说,2014 年之后的 Android 设备都支持。它的压缩比固定为 4:1(RGBA),每像素 4 位。

特性 ETC2 RGB ETC2 RGBA
压缩比 6:1 4:1
每像素位数 4 bpp 8 bpp
Alpha 通道 不支持 支持(1 位或 8 位)
质量 良好 中等
我的习惯:不带 Alpha 的漫反射贴图用 ETC2 RGB,带 Alpha 的用 ETC2 RGBA。但注意,ETC2 的 Alpha 质量一般,如果边缘有半透明渐变,建议换 ASTC。

3.1.2 ASTC:高通的王牌

ASTC 是 ARM 推出的格式,灵活性远超 ETC2。它支持从 8×8 到 4×4 的块大小,对应 0.5 bpp 到 8 bpp。我一般在项目中这样选:

  • UI 贴图:ASTC 4×4(8 bpp),质量接近原始 RGBA
  • 场景漫反射:ASTC 6×6(3.56 bpp),体积和质量的平衡点
  • 法线贴图:ASTC 5×5(5.12 bpp),保留细节
  • HDR 环境贴图:ASTC 8×8(0.5 bpp),反正没人盯着看
// Unity 中批量设置 ASTC 压缩格式的脚本片段
using UnityEditor;
using UnityEngine;

public class TextureCompressor : EditorWindow
{
    [MenuItem("Tools/Batch Set ASTC")]
    static void SetASTC()
    {
        string[] guids = AssetDatabase.FindAssets("t:Texture2D", 
            new[] { "Assets/Textures" });
        
        foreach (string guid in guids)
        {
            string path = AssetDatabase.GUIDToAssetPath(guid);
            TextureImporter importer = AssetImporter.GetAtPath(path) 
                as TextureImporter;
            
            if (importer == null) continue;
            
            // 设置 Android 平台为 ASTC 6×6
            TextureImporterPlatformSettings settings = 
                importer.GetPlatformTextureSettings("Android");
            settings.overridden = true;
            settings.format = TextureImporterFormat.ASTC_6x6;
            importer.SetPlatformTextureSettings(settings);
            
            importer.SaveAndReimport();
        }
        
        Debug.Log("批量压缩完成");
    }
}
我曾经踩过的坑:有一款游戏在小米 6 上跑得好好的,换到华为麒麟 990 上纹理全花了。查了半天,发现是 ASTC 的块大小选得太小(4×4),部分 GPU 的硬件解码器对 4×4 支持不完整。后来统一改成 6×6,问题解决。

3.2 音频压缩:Vorbis 与 Opus

音频压缩常被忽视,但它的体积占比其实不小。一个 3 分钟的 BGM,44.1kHz 16bit 立体声 WAV 是 30MB。不压缩?项目包体直接翻倍。

3.2.1 Vorbis:老当益壮

Vorbis(.ogg)是游戏界的老兵。它的优势是解码速度快,兼容性极好。我一般用在:

  • 背景音乐:128-192 kbps,人耳几乎听不出区别
  • 环境音效:96-128 kbps,反正被其他声音盖住
  • 语音对白:64-96 kbps,保留中频清晰度

3.2.2 Opus:新一代王者

Opus 是后起之秀。同样码率下,它的音质比 Vorbis 好 15-20%。我个人的建议是:

场景 推荐格式 码率 理由
BGM Opus 96 kbps 体积比 Vorbis 小 30%,音质更好
语音 Opus 48 kbps 专门优化过语音编码
短音效 Vorbis 128 kbps 解码延迟更低
旧设备兼容 Vorbis 128 kbps 部分老 GPU 硬解不支持 Opus
// FFmpeg 批量转换音频脚本
# 转 Opus(推荐)
ffmpeg -i input.wav -c:a libopus -b:a 96k output.ogg

# 转 Vorbis(兼容)
ffmpeg -i input.wav -c:a libvorbis -b:a 128k output.ogg

# 批量处理
for f in *.wav; do
    ffmpeg -i "$f" -c:a libopus -b:a 96k "${f%.wav}.ogg"
done
避坑指南:我曾经把一段 5 分钟的 BGM 压成 Opus 32 kbps,结果在游戏里听起来像收音机。后来定了个规矩:BGM 不低于 96 kbps,语音不低于 48 kbps。低于这个阈值,压缩伪影会严重影响体验。

3.3 模型 LOD 与网格压缩

模型压缩分两个层面:LOD(细节层次)和网格数据压缩。前者减少绘制三角形数,后者减少顶点数据量。

3.3.1 LOD 策略

LOD 的核心是「远处少画点」。我常用的策略是:

  • LOD0:原始模型,100% 顶点数,近距离使用
  • LOD1:减面 50%,中距离使用
  • LOD2:减面 75%,远距离使用
  • LOD3:减面 90%,极远距离或使用 Billboard

切换距离怎么定?我有个经验公式:

// LOD 切换距离计算
// 假设模型包围盒半径为 R
float lod0Distance = R * 5;    // 5倍半径内用最高模
float lod1Distance = R * 15;   // 15倍半径内用中模
float lod2Distance = R * 40;   // 40倍半径内用低模
// 超过 40 倍半径,用 Billboard 或直接不渲染

3.3.2 网格压缩

网格数据压缩主要针对顶点属性:位置、法线、UV、切线。我推荐使用 OpenGL 的 GL_OES_vertex_half_float 扩展:

属性 传统格式 压缩格式 节省
位置 float × 3 (12B) half × 3 (6B) 50%
法线 float × 3 (12B) SNORM × 4 (4B) 67%
UV float × 2 (8B) half × 2 (4B) 50%
切线 float × 4 (16B) SNORM × 4 (4B) 75%
// 使用 half float 的顶点结构体(C++)
struct CompressedVertex {
    // 位置:half float
    uint16_t x, y, z;
    
    // 法线:SNORM 4 字节(x,y,z,w),w 存储符号
    int8_t nx, ny, nz, nw;
    
    // UV:half float
    uint16_t u, v;
    
    // 切线:SNORM 4 字节
    int8_t tx, ty, tz, tw;
    
    // 总大小:6 + 4 + 4 + 4 = 18 字节
    // 原始大小:12 + 12 + 8 + 16 = 48 字节
    // 压缩率:62.5%
};
注意:half float 的精度范围是 ±65504,但精度只有约 3.3 位十进制。如果你的场景坐标超过 1000 单位,位置用 half 会丢精度。我一般只在角色模型上用 half,地形和建筑用 float。

3.4 本章知识体系

下面这张图总结了资源压缩的完整链路。你可以把它贴在工位上,每次做资源优化时对照着看。

资源压缩知识体系 资源压缩知识体系 纹理压缩 音频压缩 模型压缩 ETC2 ASTC Vorbis Opus LOD 网格压缩 纹理参数 • ETC2: 4bpp (RGBA) • ASTC: 0.5~8bpp 灵活 • 推荐: ASTC 6×6 音频参数 • BGM: Opus 96kbps • 语音: Opus 48kbps • 短音效: Vorbis 128kbps 模型参数 • LOD0: 100% 顶点 • LOD1: 50% 顶点 • 网格: half float 省 62% 目标:在可接受质量下,将资源体积压缩 60%~80%