1. 什么是纹理压缩
纹理压缩:是为了解决内存、带宽问题,专为在计算机图形渲染系统中存储纹理而使用的图像压缩技术。
1.1 图片与纹理
- 图片格式
- 图片格式是图片文件的存储格式,通常在磁盘、内存中储存和传输文件时使用。
- 例如:jpg、png、gif、bmp等
- 纹理格式
- 纹理格式是显卡能够直接进行采样的纹理数据格式,通常在向显卡中加载纹理时使用。
- 纹理管线
- 纹理压缩格式基于块压缩,能够更快读取像素所需字节块进行解压所以支持随机访问。
- 图片压缩格式基于整张图片进行压缩,无法直接实现单个像素的解析。
- 图片压缩格式无法被GPU识别,还需要经CPU解压缩成非压缩纹理格式才能被识别。
2. 常见纹理压缩格式
2.1 非压缩格式
非压缩格式 | |
---|---|
RGBA8888(RGBA32) | 一个像素32位,包含A通道(一个像素消耗4字节) |
RGBA4444(RGBA16) | 一个像素16位,包含A通道(一个像素消耗2字节) |
RGB888(RGB24) | 一个像素24位,无A通道(一个像素消耗3字节) |
RGB565(RGB16) | 一个像素16位,无A通道(一个像素消耗2字节) |
2.2 压缩格式
DXTC
DXTC纹理压缩格式来源于S3公司提出的S3TC算法,基本思想是把4x4的像素块压缩成一个64或128位的数据块,优点是创建了一个固定大小且独立的编码片段,没有共享查找表或其他依赖关系,简化了解码过程。
DXT1(BC1)
- 每个块有2个16位RGB颜色值(RGB565),代表了此4x4像素块中颜色极端值,然后通过线性插值计算出两个中间颜色值,16个2位索引值则表示了每一个像素的颜色值索引;
- (索引2个极端颜色+2个计算中间颜色)
- 适用于不具有透明度信息的贴图(或一位(0、1)透明信息-完全不透明或完全透明)
- 有透明信息时,只计算一个中间颜色值,剩下的一个索引表示透明信息
- 参照RGB24的压缩率-64/(24*16) =1/6
DXT2/3(BC2)
- DXT2/3与DXT1类似,表示颜色信息的64位数据块不变,另外附加了64位数据来表示每个像素的Alpha信息,整个数据块变为128位
- 每个像素占用8位,0-3表示透明信息,4-7表示颜色信息
- 压缩率(RGBA32):128/(32*16) = 1/4
DXT4/5(BC3)
- DXT4/5与DXT2/3的差异在于其Alpha信息使用了线性插值,表示颜色信息的64位数据块依然不变,Alpha信息则由2个8位Alpha极端值和16个3位索引值组成。
- 压缩率(RGBA32):128/(32*16) = 1/4
在Unity内贴图类型选为法线后会采用DXTnm压缩格式(居于DXT5),该格式会把法线贴图R通道存入A通道,然后RB通道清除为1,这样可以将法线XY信息分别存入到RGB/A中分别进行压缩,以获得更高的精度,然后再根据XY构建出Z通道数据。
ATI1/2
ATI1
- 为ATI公司开发的纹理压缩格式,也被称为BC4,其每个数据块存储单个颜色的数据通道,以与DXT5中的Alpha数据相同的方式进行编码,常用于存储高度图,光滑度贴图,效果与原始图像基本无差异;
- 压缩率(R8):64/(8*16)=1/2
ATI2
- 也被称为BC5,每个块中存储两个颜色通道的数据,同上以与DX5中Alpha数据相同的方式进行编码,相当于存储了两个BC4块。
- 压缩率(RG16):128/(8*16)=1/2
如果是在将法线存储在XY双通道中采用BC5格式压缩,由于每个通道都有自己的索引,因此法线贴图XY信息可以比在BC1中保留更多的保真度,缺点是需要使用两倍内存,也需要更多带宽才能将纹理传递到着色器中;
BC6/7
仅在D3D11级图形硬件中受支持,他们每个块占用16字节,BC7针对8为RGB或RGBA数据,BC6针对RGB半精度浮点数据,因此BC6是唯一一个可以原生存储HDR的BC格式
- BC6是专门针对HDR图像设计的压缩算法,压缩比为1/6
- BC7是专门针对LDR图像设计的压缩算法,压缩比为1/3
- 该格式用于高质量的RGBA压缩,可以显著减少由于压缩法线带来的错误效果
ETC
DirectX选择了DXTC作为标准压缩格式,对于Opengl则选择了爱立信研发的ETC格式,几乎所有安卓设备都可以支持ETC压缩,所以其在移动平台上被广泛使用。
ETC与DXTC具有相同的特点,将4x4的像素单元压缩成64位数据块,并将像素单元水平或竖直朝向分为两个区块,每个像素颜色等于基础颜色加上索引指向的亮度范围。
ETC1
- 每个数据块分区中的4位亮度索引信息会从16个内置亮度表中获取当前像素单元对应的亮度表,每个像素的2位像素索引值可以从亮度表的四个值中选取对应的亮度补充值
- 压缩率(RGB24):64/(16*24)=1/6
ETC2
- ETC1的扩展,支持了Alpha通道的压缩,硬件要求Opengl ES3.0和Opengl4.3以上
差别
- ETC1要求长宽为2的幂次的贴图,适用于所有安卓设备,压缩率比较高,但不适合带Alpha通道的贴图
- ETC2要求长宽能被4整除的贴图,设备有硬件要求,支持Alpha通道压缩,内存占用大于ETC1
ASTC
ASTC是ARM和AMD联合开发的纹理压缩格式,各项指标都不错,
- 优点
- 可根据不同图片选择不同压缩率的算法
- 图片不需要为2的幂次
- 同时支持LDR和HDR
- 缺点
- 兼容性不够完善
- 解码时间较长
ASTC也是基于块的压缩算法,与BC7类似,数据块大小固定为128位,不同的是块中像素数量可变,从4x4到12x12像素都有。
每个数据块中存储了两个插值端点,但不一定存储的是颜色信息,也可能是Layer信息,这样可以用来对Normal或Alpha进行更好的压缩
对于块中每个像素,存储对应插值端点的权重,存储的权重数量可以少于纹素数量,可通过插值得到每一个纹素的权重值,然后再进行颜色的计算。
- 数据块构成
- 11位:权重、高度信息、特殊块标识
- 2位:Part数量
- 4位:16种插值端点模式(如LDR/HDR,RGB/RGBA)
- 111位:插值端点信息,纹素权重值,配置信息
PVRTC
由Imagination公司专为PowerVR显卡设计,仅支持Iphone,Ipad和部分安卓机。
不同于DXTC和ETC这类基于块的算法,PVRTC将图像分为了低频和高频信号,低频信号由两张低分辨率图像AB组成,高频信号则是低精度的调制图像,记录了每个像素混合的权重,解码时AB图像经过双线性插值放大,然后根据调制图像的权重进行混合
- PVRTC
- PVRTC 2-bpp(bit per pixel)
- PVRTC 4-bpp把一个4x4的像素单元压缩成一个64位数据块,每一个块中存储一个32位(每个像素2位)的调制数据,一个1位的调制标识,15位(RGB555/RGBA4443)的颜色A,1位颜色A不透明标识(决定按照RGB还是RGBA进行存储),14位(RGB554/RGBA4433)颜色B,1位颜色B不透明标识
- 压缩率(RGB):64/(24*16) = 1/6
- 压缩率(RGBA):64/(32*16) = 1/8
2.3 总结
- 画质比较
- RGBA>ASTC 4x4>ASTC6x6>ETC2 ≈ETC1
- 压缩比
压缩格式 | 压缩率 |
---|---|
DXT1 | 1/6 |
DXT2/3 | 1/4 |
DXT4/5 | 1/4 |
ATI1 | 1/4 |
ATI2 | 1/4 |
BC6 | 1/6 |
BC7 | 1/3 |
ASTC | 1/4~1/35.95 |
PVRTC | 1/6 |
3. 实际应用中的选择
- PC
- 低质量使用DXT1,不支持A通道,使用DXT5格式支持A通道
- 高质量使用BC7,支持A通道
- 安卓
- 低质量使用ETC1,不支持A通道
- 低质量使用ETC2,支持A通道(Opengl ES3.0/Opengl 4.3以上版本)
- 高质量使用ASTC(Android5.0/Opengl ES3.1以上版本)
- IOS
- 高质量使用ASTC(Iphone6以上版本)
- 低质量使用PVRTC2(支持Iphone6以下版本)
作业
结合今天课程,针对ASTC与ETC2这两个格式进行打包测试,分析内存占用占比。
3.7的作业正好也差不多。。。放个链接
https://xzyw7.github.io/post/Lyp-tjMR_/#%E4%BD%9C%E4%B8%9A
(ASTC6x6&ETC2)最后包体的体积是非常接近的
ASCT
ETC2
就包体而言ASCT6x6是更大一些的,但是最后的内存占用却小了一些。
(帧率的差别应该主要来源于CPU的性能差别,ASTC的CPU性能占用稍高,也就是解码的消耗)
再用单张贴图的压缩结果来看看各种压缩格式的效果(ASTC压缩实在是有点猛,相比也会占用更多CPU时间)
参考资料
[1] https://www.bilibili.com/video/BV1Av411K7bt
【技术美术百人计划】图形 3.6 纹理压缩——包体瘦身术