DXTC(或 BC)为微软为 DX 而推出的基于 block 的贴图压缩格式,其主要采用调色板的原理来进行压缩。
BC1:
基于 4x4block 来进行,不含有 alpha 通道,每个 block 内记录两个 16bits 的颜色做为基准颜色,然后解压时再使用两个基准色调制出另外两个颜色做为块内 4 个压缩颜色。其计算方式为:
basecolor2 = 2/3 *basecolor0 + 1/3 * basecolor1
basecolro3 = 1/3 *basecolor0 + 2/3 * basecolor1
对于每个块内的 texel,存储 2bits 的索引,用来指向到 4 个基准颜色中的一个。所以对于 BC1 的压缩状态为 64bits:
BC3:
在 BC1 的基础上支持 alpha 通道。首先,颜色的存储方式与 BC1 相同,需要 64bits;对于 alpha 部分,使用与颜色部分相同的策略来处理。在 block 存储两个基准的 alpha 值,然后在其基础上插值得到其它 6 个共计 8 个 alpha 值,来做为 alpha 的调色板;然后对于每个 texel 存储一个 3bits 的索引,用来指向到这 8 个 alpha 中的一个。所以其对应的存储状态为:
同时,两个 alpha 值中的不同的标记情况也对应着不同的插值操作:
若 alpha0 > alpha1
alphai = (7 - i) / 7 *alpha0 + i/7 * alpha1;(2<=i<=7);
若 alpha0 < alpha1
alphai = (5 - i) / 5 *alpha0 + i/5 * alpha1;(2<=i<=5);
alpha6 = 0;
alpha7=255;
ETC 压缩算法采用将图像中的 chromatic 和 luminance 分开存储的方式,而在解码时使用 luminance 对 chromatic 进行调制进而重现原始图像信息。
ETC 也主要有两种方法:ETC1 和改进后的 ETC2。
ETC1:
采用 4x2 的 block 进行分割(原始为 4224=192,压缩后为 32,压缩率为 6):
对于所有图片都使用一个全局的 16 个组 table codeword,每组中有四个数值,且其中是有规律可循的,如下所示:
改进后采用 4x4 的 block 进行分割(原始为 4424= 384, 压缩后为 64, 压缩率为 6):
主要针对某两个 4x2 的 block 间的颜色差异相对较小,因而可以使用一个更多的 bit 来表示一个更高精度的 basecolor,而另外一个 basecolor 则在其基础上通过一个 bit 较小的 diff 来进行动态计算得来。
对于所有图片都使用一个全局的 8 个组 table codeword,每组中有四个数值:
ETC2
根据 ETC1 的实现方式,如果其块内的颜色分布不均匀的话,则其存储的两个 basecolor 会较远的分布于插值趋线的较远的两侧,进行解压后会得到较低的压缩质量
改进主要针对 ETC1 中的 diff 为 1 的情况下展开,即 basecolor 为 RGB555 和差值 RGB333,此时另外一个颜色值 = RGB555 + dRGB333,而其中的三个通道也是可以独立开来计算的,比如对于红色通道即为 R = R5 + dR3,此时,若其中的 R5 为 0 且 dR3 为负值时得到的红色通道值就没有意义,此种情况下就可以对该 block 重新定义编码方式
针对 ETC1 不支持透明通道的改进,用 ETC2 可以支持透明通道,不过要求 OpenGL ES3.0 及以上(Android4.3+),目前基本覆盖率在 9 成以上
PVRTC 的不是基于 block 的方式生成的,但是却也可以理解为以 block 方式组织的。其生成压缩后包含两张 (w/4,h/4) 大小的缩略图(w,h 为原始图片的宽和高,可以理解为第 4 级的 mipmap,但生成过程会比较 mipmap 的复杂),其中的每个 pixel 映射并对应到原始图像中的一个 64x64 的 block 上;然后使用 1 张与原始图像大小相同的 modulate 图,对应的每个 pixel 占 2 个 bits,也即可对应四种调制方式,通过几种不同的调制方式还原出近似的原始像素值。
压缩后的一个 4x4 的 block 中的 bits 的组成内容为:
通过调节上述两张缩略图的大小,可以相应的改变对应的压缩比,比如由(w/4,h/4)修改为(w/8,h/4),而其它的映射方式不变,即可将压缩比增大一倍。
ASTC 中 ARM 研发的一种较新的贴图压缩格式,相对于上述几种方法具有较多的优势,其应该会慢慢成为之后移动设备上贴图压缩的主要标准和主流。其主要具有如下的特性:
ASTC 同样是基于 block 的压缩方式,但块的大小却较支持多种尺寸,比如从基本的 4x4 到 12x12,而且块的宽高也不限于 pot,比如 6x5;每个块内的内容用 128bits 来进行存储,因而不同的块就对应着不同的压缩率。
对于每个块,同样存储两个插值端点,称为 endpoints,但是这里的 endpoints 不一定是基于颜色的(RGBA),也可以基于 layer,比如对于 R,G,B,A 甚或其中的组合如 RG 等,这样的话就可以用来对 normal map 或 alpha map 进行更好的压缩;
对于块中的每个 texel,存储其对应于 endpoints 的插件 weight,但是存储的 weight 数量可以比 texel 少,特别是对于规格较大的块(比如 12x12),这种情况下会首先对于每个 texel 通过线性插值得到其对就应的 weight,然后再进行颜色的计算;
对于块内颜色分布较为复杂的情况,分析块内颜色的分布,然后做 partition,对于每个 partition 进行分别的处理(与 ETC2 中将颜色分布对应到具体的预知分布模式中的处理方法不同),分别存储其对应的 endpoints;这样一来对于块内的某个 texel 进行取值时就先定位其对应的 partition,然后再计算在其在对应的小子块内的颜色。
块内信息的存储采用了 BISE 的方式来进行压缩,尽可能的节省对应的存储空间。比如对于一组 5 个表示范围已知的整型数值,采用 BISE 存储后可节省两个 bits,这样就使用每个块内较大量的数据存储于 128bits 内成为可能;
对于单 layer 的一个 block 内的 bits 组织大概如下所示:
更多的细节可以看这里
4.1 Bounded Integer sequence encoding
主要是针对范围限定的整数序列进行压缩存储进而节省空间。比如对于三个数 4,78,55,其直接用 binary 的表示为 0000100,1001110,0110111,直接存储二进制序列的话需要 7bits * 3 = 21bits(在已知最大范围为 78 的情况下,不需要存储满 8bits)。但是能不能在 21bits 的基础上再减少呢?BISE 就是实现这样的目的的。
假设序列的范围为 N,对应的 bit 位数为 n:
这里的背后其实是基于这样的一个事实,比如在基于 3 的压缩中,如果 N<=32n-2,那么在 N 的最高两位 bit 上,其并不会出现 22 种情况的所有组合(因其大小是受限的),到少 11 这样的组合就是没有的,否则其对应的值必定大于 N。所以 BISE 压缩就是将受限的整数序列中的前两位数据中的无效 bits 进行合理使用。比如,在上述 4,78,55 的序列中,78 <= 5 * 2^4 = 80,所以可以使用基于 5 的 BISE,将三个数的二进制序列构造为{000 0100, 100 1100, 011 0111},高三位的组合为{000,100,011},因这三个 3 位 bits 序列中的最大值是 5,所以每三个 bits 最多有 5 种情况,那么这个高三位组合的序列共可能有 5^3=125 种组合情况,这样的话就可以使用 7bits 的空间来存储所有的这些组合,如此一来就可以将原来 33=9bits 的存储空间存储在 7bits 中,进而达到压缩的目的。