← ALL ARTICLES
纹理技术5 MIN READ

纹理压缩格式

全库目录221
本文目录13

一张 PNG 在磁盘上很小,导入后却可能占去数十 MB 显存。磁盘压缩与 GPU 采样使用的是两种表示:GPU 要随机访问纹素,通常把数据存成固定尺寸的可解码块。我们因此从块的字节数算预算,再根据法线、颜色、Alpha 和平台支持选择格式。

GPU 纹理压缩

PNG/JPEG 主要减少磁盘和下载大小,GPU 通常不能直接按任意 Texel 随机采样它们。运行时 GPU 压缩格式把纹理分成固定大小 Block,每个 Block 解码出若干 Texel,支持随机访问。

优点:

  • 减少 VRAM;
  • 减少纹理带宽;
  • 保持硬件直接采样。

限制:

  • Block 内像素共享端点或模式,容易产生块状和颜色误差;
  • 质量与内容类型有关;
  • 即使图片大面积透明,GPU 占用通常仍由尺寸、格式和 Mip 决定;
  • 运行时重新压缩成本高。

BC 格式

格式常见用途主要特点
BC1RGB、可选 1-bit Alpha4 bpp;适合无平滑 Alpha 的颜色
BC3RGBA8 bpp;颜色类似 BC1,Alpha 独立压缩
BC4单通道数据4 bpp;Mask、高度、灰度数据
BC5双通道数据8 bpp;常用于 Normal XY
BC6HHDR RGB8 bpp;浮点 HDR 环境数据
BC7高质量 RGB/RGBA8 bpp;多种模式,质量高、编码更慢

BC5法线通常保存切线空间X/Y,再按 z=sqrt(max(0,1-x*x-y*y)) 重建正半球Z,并归一化。UNORM需要先从[0,1]解码到[-1,1],SNORM直接按有符号值读取;此表示要求法线位于选定半球,不能表示任意正负Z方向。相比把三通道法线塞进普通颜色压缩,它给两个关键方向分量更稳定的精度。

BC1 的“1-bit Alpha”并不适合平滑透明。BC3 是否比 BC7 更合适,要看目标平台、编码质量、内容和构建时间。

移动端格式

ETC2/EAC

OpenGL ES 3 级移动设备常见。ETC2 处理 RGB/RGBA,EAC 适合单/双通道数据。

ASTC

支持多种 Block 尺寸,例如 4x4、6x6、8x8。Block 越大,每像素位数越低、占用越小,但细节损失更明显。

ASTC 的 LDR 与 HDR 支持要分别查询。设备支持 LDR ASTC 并不意味着支持 HDR profile;构建时按目标 API 与设备能力选择,回退格式也要计入内存预算。

PVRTC

较老的 PowerVR/iOS 设备常见。它不是普通独立 4x4 Block 思路,低分辨率、小图和 Alpha 边缘可能出现明显扩散伪影。

压缩格式选择

先按数据语义:

  • Base Color:BC1/BC7、ETC2、ASTC;
  • 平滑 Alpha 颜色:BC3/BC7 或合适 ASTC;
  • Normal:BC5、EAC RG、ASTC 双通道思路;
  • 单通道 Mask:BC4、EAC R;
  • HDR Environment:BC6H 或 HDR ASTC;
  • UI:根据文字边缘、Alpha 和平台决定,不能直接套场景纹理规则。

再看目标平台、质量、内存、带宽、包体和编码时间。最终应检查目标设备上的解码结果,而不是只看源 PNG。

块存储预算

压缩资源按完整块存储,最后不足一块的尺寸也要向上取整。以下 Python 用 BC1 的 4×4 像素、8 字节块估算一个完整二维 mip 链,不计驱动对齐与资源元数据。

python
width, height = 1024, 1024
block_width, block_height, block_bytes = 4, 4, 8
total = 0
while True:
    columns = (width + block_width - 1) // block_width
    rows = (height + block_height - 1) // block_height
    total += columns * rows * block_bytes
    if width == 1 and height == 1:
        break
    width = max(1, width // 2)
    height = max(1, height // 2)
print(total)

ASTC每块固定16字节,因此4×4、6×6、8×8分别为8、约3.56、2 bpp;改变的是覆盖纹素数。数组层和Cube面再乘对应数量。长宽同时减半的较大二维纹理,完整mip链通常接近基级的三分之四倍(约增加三分之一)。每降一级,像素数约为前一级的四分之一,级数相加约为 1 + 1/4 + 1/16 + … = 4/3。小mip的完整块成本、细长尺寸和资源对齐都会使实际比例偏离近似。预算函数能计算任意正尺寸的块载荷,但目标API可能限制资源基级尺寸、格式用途和拷贝对齐,不能把载荷可计算等同于资源可创建。

端点与索引的误差来源

BC1的4×4块保存两个RGB565端点和16个2位索引,总计8字节。解码器由端点生成有限调色板,每个纹素只能选其中一种。一个块内若同时出现多种独立颜色、窄边或平滑渐变,就可能无法用这条颜色线段逼近。带透明的模式还减少了可用不透明颜色。BC5将两个通道分开编码,降低通道间共同颜色线段的约束,但方向解码误差仍会影响高光。

BC7用更多端点模式和分区改善复杂颜色块的拟合,固定128位块长意味着这些模式仍需在端点精度、索引和分区之间分配位数。编码耗时取决于搜索策略,解码质量需要按实际素材比较。

一个颜色块的重建

取BC1不透明四颜色模式,两个RGB565端点为红(1,0,0)与蓝(0,0,1),其编码大小关系满足四颜色模式。解码调色板为红、蓝、(2/3,0,1/3)、(1/3,0,2/3),每个纹素的2位索引只选择这四项之一。即使原图某纹素是纯绿,它也无法在这条红蓝线段上重建。

编码器可以重新选择端点以减小整块误差,但无法让16个纹素各有独立RGB。窄绿线与红蓝背景处在同一个4×4块时,线色或背景必须妥协;把图片放大查看块边并改变块对齐,可以区分压缩误差与采样模糊。三颜色透明模式的端点关系和调色板不同,不能沿用本例索引解释。

验证方法

  • 对法线、渐变、Alpha 和 HDR 各制作测试纹理,对比未压缩基准。
  • 查询设备格式支持,验证构建产物没有静默转为高内存回退格式。
  • 记录尺寸、mip、块数、实际资源字节及视觉误差。

本机机制检查:BC1 1024×1024 的完整 mip 链在本机得到 699064 字节;这是块载荷,不包含驱动对齐。检查代码见 reference.py,运行 python 知识库/examples/mechanisms/reference.py。引擎画面、GPU捕获与性能另外验证。

相关主题

参考资料