几种主流贴图压缩算法的实现原理详解
发表于2018-03-13
对于不同的项目其中关于贴图压缩这块需要针对不同的平台做不同的设置,下面就和大家介绍下在各种平台中常使用的几种贴图压缩格式及其细节,以便更加适宜地选择在特定设备下的压缩格式以便节省资源。关于移动平台和硬件设备与压缩格式的对应关系可以参考下这里,基本上比较清楚了。
1. DXTC
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:
- 32bits:两个RGB565格式的基准颜色;
- 32bits:16个2bits的索引;
BC3:
在BC1的基础上支持alpha通道。首先,颜色的存储方式与BC1相同,需要64bits;对于alpha部分,使用与颜色部分相同的策略来处理。在block存储两个基准的alpha值,然后在其基础上插值得到其它6个共计8个alpha值,来做为alpha的调色板;然后对于每个texel存储一个3bits的索引,用来指向到这8个alpha中的一个。所以其对应的存储状态为:
- 32bits:两个RGB565格式的基准颜色;
- 32bits:16个2bits的颜色索引;
- 48bits:16个3bits的alpha索引;
- 16bits:2个8bits的基准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;
2. ETC
ETC压缩算法采用将图像中的chromatic和luminance分开存储的方式,而在解码时使用luminance对chromatic进行调制进而重现原始图像信息。
ETC也主要有两种方法:ETC1和改进后的ETC2。
ETC1:
采用4x2的block进行分割(原始为4*2*24=192,压缩后为32,压缩率为6):
对于所有图片都使用一个全局的16个组table codeword,每组中有四个数值,且其中是有规律可循的,如下所示:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
-8 | -12 | -31 | -34 | -50 | -47 | -80 | -127 | -16 | -24 | -62 | -68 | -100 | -94 | -160 | -254 |
-2 | -4 | -6 | -12 | -8 | -19 | -28 | -42 | -4 | -8 | -12 | -24 | -16 | -38 | -56 | -84 |
2 | 4 | 6 | 12 | 8 | 19 | 28 | 42 | 4 | 8 | 12 | 24 | 16 | 38 | 56 | 84 |
8 | 12 | 31 | 34 | 50 | 47 | 80 | 127 | 16 | 24 | 62 | 68 | 100 | 94 | 160 | 254 |
- 12bits:RBG444的一个basecolor,其在使用是需要被扩展到8bits;每个block使用32bits进行编辑存储;比如对于RGB=(0,2,15) -> (0000 ,0010 , 1111),扩展后为(000000,00100010 , 11111111)->(0 , 34 , 255),扩展方法为直接将原始4位复制后拼接为8位即可;
- 4bits:用来索引16个table codeword中的一组,比如{-10 , -1 , 4 , 7};
- 16bits:对于block中的每个pixel分配2bits,就有4个值,用来索引当前像素对应于table codeword中的每个modifier,该modifier需要组成三个通道的调整值,比如,对于某个pixel其对应的modifier索引值为2,也即对应上述table codeword中的4,如此一来该pixel的RGB = (0,34,255) + (4,4,4)=(4,38,259),最后需要将其clamp至0,255,因而即为(4,38,255)。
改进后采用4x4的block进行分割(原始为4*4*24= 384, 压缩后为64, 压缩率为6):
主要针对某两个4x2的block间的颜色差异相对较小,因而可以使用一个更多的bit来表示一个更高精度的basecolor,而另外一个basecolor则在其基础上通过一个bit较小的diff来进行动态计算得来。
对于所有图片都使用一个全局的8个组table codeword,每组中有四个数值:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
-8 | -17 | -29 | -42 | -60 | -80 | -106 | -183 |
-2 | -5 | -9 | -13 | -18 | -24 | -33 | -47 |
2 | 5 | 9 | 13 | 18 | 24 | 33 | 47 |
8 | 17 | 29 | 42 | 60 | 80 | 106 | 183 |
- 1bit:用来记录两个字block是采用常规的4*2编码还是基于差值的编码;
- 1bit:用来记录4x4的block内两个子block的朝向(可以两个4*2,也可以两个2*4)
- 32bits:对于16个pixel,每个分配2bits的索引,指向到对应的modifier;
- 6bits:对于每个子block,有一个3bits的索引,指向8个table codeword中的某一个(由原始的16组codeword缩减为8个);
- 24bits: 分别对应两个basecolor。对于常规编码时,则是两个RGB444,然后对每个扩展到RGB888;对于差值编码时,则是一个RGB555(精度较高)的basecolor和一个差值RGB333(较低精度),先计算出先求值,然后再扩展。
ETC2:
根据ETC1的实现方式,如果其块内的颜色分布不均匀的话,则其存储的两个basecolor会较远的分布于插值趋线的较远的两侧,进行解压后会得到较低的压缩质量,
因而ETC2就是解决如何针对这些较为特殊的颜色分布来选择更加优化的压缩策略。
改进主要针对ETC1中的diff为1的情况下展开,即basecolor为RGB555和差值RGB333,此时另外一个颜色值= RGB555 + dRGB333,而其中的三个通道也是可以独立开来计算的,比如对于红色通道即为R = R5 + dR3,此时,若其中的R5为0且dR3为负值时得到的红色通道值就没有意义,此种情况下就可以对该block重新定义编码方式。
1. 对于红色通道的溢出情况:
- 1bit: diff mode
- 8bits: R5,dR3,
剩余64-1-8 =55bits可用来存储其它的信息,但是注意这些其中的R5与dR3之间的溢出方式有不同的16种,而也可以将其转换为对应的数据存储(可以存储4bits的信息),因而整个信息存储位数为59bits.
2. 对于绿色通道的溢出情况:
- 1bit: diff mode
- 8bits: R5,dR3
- 8bits: G5, dG3
剩余64-1-8-8 =47bits可用来存储其它的信息,但是注意此时R通道是没有溢出的,共有256-16种状态,因而其可以存储7bits的信息,G通道是有溢出的,其与R通道的溢出相同,也有16种不同的状态,而也可以将其转换为对应的数据存储(可以存储4bits的信息),所以通过RG两通道的状态可以额外存储的信息bits数为7+4=11bits。所有在这种情况下的信息存储总数量为47+11=58bits。
3. 对于蓝色通道的溢出情况:
- 1bit: diff mode
- 8bits: R5,dR3
- 8bits: G5, dG3
- 8bits:B5, dB3
剩余64-1-8-8-8=39bits可用来存储其它的信息。同样对于RGB三个通道进行额外的信息存储之后的存储空间为7+7+4=18bits。所以此种情况下的信息存储空间即为:39+18=57bits。
上述操作就巧妙地利用了三个通道中的信息,来得到扩展的存储空间,然后使用这些存储空间来对图像信息进行编码与压缩即可。但注意:这些通过三个通道的溢出情况来确定对应模式,并将其中的溢出状态也利用为对应的存储空间,看起来比较绕,为什么不直接使用1位之外的其它63bits进行数据存储呢?这里主要是因为原始的ETC1采用了三个通道这样的存储方式,而ETC2又必须要兼容ETC1,所以只能使用如此的方法。
接下来即需要合理利用57,58,59这三种情况下的bits存储空间来进行原始数据的压缩。针对颜色分布不均匀的状态,将其细分为了三种不同的分布情况:
T字型分布,一部分颜色沿插值趋线分布,另外的颜色分布于距离较远的位置上,这里将颜色分为不同的两组,每组颜色统计出其对应的basecolor0,basecolor1(对应图中的蓝色点),每个basecolor为RGB444,而对于位于右下方的basecolor0存储一个3bits的索引值,用来索引到一个operator(共有8个),然后得到其周围的两上basecolor3, basecolor4,如此一来就有4个basecolor,而block中的每个pixel均索引到4个basecolor中的一个。因而共需要存储位数为:
- 12bits: RGB444 basecolor0
- 12bits: RGB444 basecolor1
- 3bits: operator
- 32bits: 对于16个pixel,每个2bits的索引值
共计为:59bits
H字型分布,两部分的颜色均有不同的分布趋向,同样的原理,统计出两组的basecolor,然后使用operator分别对两个basecolor扩展为两个basecolor(注意:对T字型只需要扩展一个),然后用4个新的basecolor来重建block中每个像素的颜色信息。
- 24bits: RGB444,RGB444两个basecolor
- 3bits: operator
- 32bits:对于16个pixel,每个2bits的索引值
平面分布型,其主要针对block块内的颜色分布于4个角落上的情形,如下所示:
这里对应的计算模型也就比较简单直观,可以直接存储C0,CH与CV三个颜色值,可将其处理为三角形(或四边形)上的三个顶点(对应的顶点坐标为00,30,03,33),然后对block内每个pixel点上的颜色通过插值的方法得到即可,这里每个pixel点的坐标可以使用其在block块内的位置即可(如00,01,02,03,10,11,12,13……)。此种情况下不需要其它的信息,所有我们可以直接把bits信息全部用来存储c0,ch,cv三个basecolor即可,在57bits的情况下可得到三个颜色的存储为19,因而每个basecolorr的存储格式为RGB676。
通过上述可以看出,ETC2对于原始图像的分析比ETC1要更为多样,且要兼容ETC1的格式,因而对应的压缩算法会更加复杂。ETC存储格式是没有处理alpha信息,因而其不能直接应用于半透明图像的压缩,但是这里也有可先的方案来在ETC的基础上使用alpha通道:ETC Texture compression and alphachannel handling
3. PVRTC
PVRTC的不是基于block的方式生成的,但是却也可以理解为以block方式组织的。其生成压缩后包含两张(w/4,h/4)大小的缩略图(w,h为原始图片的宽和高,可以理解为第4级的mipmap,但生成过程会比较mipmap的复杂),其中的每个pixel映射并对应到原始图像中的一个64x64的block上;然后使用1张与原始图像大小相同的modulate图,对应的每个pixel占2个bits,也即可对应四种调制方式,通过几种不同的调制方式还原出近似的原始像素值。
压缩后的一个4x4的block中的bits的组成内容为:
- 1bit:对应的融合方式,透明或不透明;
- 32bits:对应于16个pixel,每个pixel有2bits的调制因子;
- 31bits:对应两个缩略图中的该块映射到的两个像素上的颜色,若是透明模式,则两个颜色为RGBA44431,RGBA34431;若是不透明模式,则两个颜色为RGBA5551,RGBA4551;
两种模式下的调制因子分别为:
不透明 | 透明 | |
00 | 0/8 | 0/8 |
01 | 3/8 | 4/8 |
10 | 5/8 | -- |
11 | 8/8 | 8/8 |
透明情况下的10调制因子会强制设置当前pixel的alpha为0;
通过调节上述两张缩略图的大小,可以相应的改变对应的压缩比,比如由(w/4,h/4)修改为(w/8,h/4),而其它的映射方式不变,即可将压缩比增大一倍。
4. ASTC
ASTC中ARM研发的一种较新的贴图压缩格式,相对于上述几种方法具有较多的优势,其应该会慢慢成为之后移动设备上贴图压缩的主要标准和主流。其主要具有如下的特性:
- 较高的灵活性;
- 可变的压缩率;
- 支持2d/3d贴图;
- 适用于移动平台;
- 支持LDR/HDR贴图内容;
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组织大概如下所示:
- 11bits: 存储weight, height, 以及特殊块的标识,比如void-extent等;
- 2bits: part数量;
- 4bits: 存储16种不同的endpoints的模式,比如是LDR或HDR,RGB或是RGBA;
- 111bit:其中存储endpoints,texel weight以及其它的配置信息,(注意,每种具体的存储大小是可变的,因其采用BISE进行压缩放置);
更多的细节可以看这里
4.1 Bounded Integer sequence encoding
主要是针对范围限定的整数序列进行压缩存储进而节省空间。比如对于三个数4,78,55,其直接用binary的表示为0000100,1001110,0110111,直接存储二进制序列的话需要7bits * 3 = 21bits(在已知最大范围为78的情况下,不需要存储满8bits)。但是能不能在21bits的基础上再减少呢?BISE就是实现这样的目的的。
假设序列的范围为N,对应的bit位数为n:
- 若N<= 3*2^n-2,则其可用基于5的BISE压缩;
- 若N<=5*2^n-3,则其可用基于3的BISE压缩。
这里的背后其实是基于这样的一个事实,比如在基于3的压缩中,如果N<=3*2^n-2,那么在N的最高两位bit上,其并不会出现2^2种情况的所有组合(因其大小是受限的),到少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的空间来存储所有的这些组合,如此一来就可以将原来3*3=9bits的存储空间存储在7bits中,进而达到压缩的目的。
来自:http://blog.csdn.net/bugrunner/article/details/50538770