4、纹理优化策略:纹理压缩格式(ETC2、ASTC)、纹理图集(Texture Atlas)、Mipmap的使用与误区
纹理,是座舱图形渲染中最吃显存的一环。我见过不少项目,帧率上不去,一查,纹理带宽爆了。说白了,纹理优化就是给显存和带宽“减负”。今天聊聊三个核心手段:压缩格式、纹理图集、Mipmap。每个都有坑,我踩过不少。
4.1 纹理压缩格式:ETC2 与 ASTC
纹理压缩不是新鲜事。但选错格式,画面直接崩。我个人习惯,移动端座舱首选 ASTC,兼容性够好,质量也高。
ETC2:老牌选手,稳但不够强
ETC2 是 OpenGL ES 3.0 的标配。所有支持 Vulkan 的座舱芯片,基本都支持它。优点是兼容性极好,几乎没有设备不支持。
但缺点也明显:压缩比固定 4:1,不支持透明通道的独立压缩。我曾在项目中用 ETC2 压缩带 alpha 的按钮纹理,结果边缘锯齿严重。后来换成 ASTC,问题解决。
| 格式 | 压缩比 | 质量 | 适用场景 |
|---|---|---|---|
| ETC2 | 4:1 | 中等 | 无透明、非关键纹理 |
| ASTC | 可变(4x4~12x12) | 高 | UI、图标、HUD 元素 |
ASTC:灵活,但别乱用
ASTC 支持从 4x4 到 12x12 的块大小。块越小,质量越高,但显存占用也大。我建议:
- UI 图标、小纹理:用 4x4 或 5x5,保证清晰度
- 背景、大图:用 8x8 或 10x10,省显存
- 法线贴图:用 6x6,平衡质量与性能
4.2 纹理图集(Texture Atlas):合并不是万能药
纹理图集,就是把多个小图拼成一张大图。好处是减少 draw call,坏处是容易踩坑。
为什么用图集?
GPU 切换纹理是有开销的。你把 100 个图标拼成一张图,原本 100 次切换变成 1 次。座舱仪表盘上图标多,这个优化很有效。
我踩过的坑
我曾经把整个 HUD 的图标塞进一张 4096x4096 的图集里。结果呢?有些图标需要频繁更新(比如车速数字),每次更新都得重新上传整张图集。显存带宽直接炸了。
后来我学乖了:
- 静态元素(背景、边框)放一张图集
- 动态元素(数字、指针)单独放,或者用动态纹理更新
- 图集尺寸别超过 2048x2048,否则 mipmap 生成会出问题
4.3 Mipmap:用得好是宝,用不好是坑
Mipmap 是预先生成的一组分辨率递减的纹理。GPU 根据物体距离自动选择合适层级。好处是减少锯齿,提升渲染质量。但很多人用错了。
什么时候必须用?
- 纹理在屏幕上缩小时(比如远处的地面、小图标)
- 纹理有高频细节(文字、细线)
- 需要各向异性过滤时(座舱的倾斜视角很常见)
什么时候别用?
- UI 元素固定大小,不缩放(比如按钮、标签)
- 纹理是动态生成的(比如摄像头画面)
- 纹理图集里子纹理间距不够(mipmap 会采样到邻居)
误区:mipmap 层级选择
GPU 自动选择 mipmap 层级,但有时会选错。比如纹理在屏幕上刚好处于两个层级之间,GPU 会做 trilinear filtering,性能开销大。我建议:
- 对性能敏感的场景,手动指定 mipmap 层级
- 或者用
GL_TEXTURE_MIN_LOD和GL_TEXTURE_MAX_LOD限制范围
// 限制 mipmap 层级范围,避免不必要的开销
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 3);
4.4 总结:我的建议
纹理优化没有银弹。我个人的工作流是这样的:
- 静态 UI 元素:ASTC 6x6 + 纹理图集(2048x2048 以内)
- 动态元素:单独纹理,不压缩,用 RGBA 直接上传
- 背景大图:ASTC 10x10 + mipmap
- 图标、小纹理:ASTC 4x4,不开 mipmap
嗯,大概就是这样。纹理这块,多测试,多调参。每个座舱项目的硬件都不一样,别指望一套方案打天下。