纹理压缩格式
全库目录221
本文目录13
一张 PNG 在磁盘上很小,导入后却可能占去数十 MB 显存。磁盘压缩与 GPU 采样使用的是两种表示:GPU 要随机访问纹素,通常把数据存成固定尺寸的可解码块。我们因此从块的字节数算预算,再根据法线、颜色、Alpha 和平台支持选择格式。
GPU 纹理压缩
PNG/JPEG 主要减少磁盘和下载大小,GPU 通常不能直接按任意 Texel 随机采样它们。运行时 GPU 压缩格式把纹理分成固定大小 Block,每个 Block 解码出若干 Texel,支持随机访问。
优点:
- 减少 VRAM;
- 减少纹理带宽;
- 保持硬件直接采样。
限制:
- Block 内像素共享端点或模式,容易产生块状和颜色误差;
- 质量与内容类型有关;
- 即使图片大面积透明,GPU 占用通常仍由尺寸、格式和 Mip 决定;
- 运行时重新压缩成本高。
BC 格式
| 格式 | 常见用途 | 主要特点 |
|---|---|---|
| BC1 | RGB、可选 1-bit Alpha | 4 bpp;适合无平滑 Alpha 的颜色 |
| BC3 | RGBA | 8 bpp;颜色类似 BC1,Alpha 独立压缩 |
| BC4 | 单通道数据 | 4 bpp;Mask、高度、灰度数据 |
| BC5 | 双通道数据 | 8 bpp;常用于 Normal XY |
| BC6H | HDR RGB | 8 bpp;浮点 HDR 环境数据 |
| BC7 | 高质量 RGB/RGBA | 8 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 链,不计驱动对齐与资源元数据。
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捕获与性能另外验证。
相关主题
参考资料
- Microsoft,Block Compression:2026-10-22核读BC1、BC4、BC5及Virtual Size versus Physical Size;D3D10的基级创建限制单独适用。
- Microsoft,BC7:128位块、八类模式与分区。
- Khronos ASTC规范源:2026-10-22核读Basic Concepts的128位块和LDR/HDR profiles;具体API能力需查询设备。