简介
贴图为图形显示效果增添了丰富的表现与细节,是增强图形效果真实性与美观性的重要元素,但同时由于包含了大量的信息,贴图对于游戏的各项性能指标如内存占用,带宽等的影响也不容忽视,尤其是带宽,当代计算平台如GPU/CPU多采用共享统一内存框架,unified memory architecture,而且由于多核CPU与GPU多线程运算的原因,对于带宽的要求与压力被进一步放大,而这些影响在移动端上尤为突出。如何使用尽可能少的数据,尽可能低的性能损耗实现最佳的图形表现,也就是所谓的高压缩比,高保真(可实现对任一位置的像素数据随机读取),就成为了贴图压缩算法的首要指标。(准确来说,贴图压缩需要兼顾内存,质量,电量消耗(电量消耗的首要因素在于图形渲染点亮屏幕,其次在于内存access)以及表现这四项内容)
当前各路设备都已经支持了实时贴图采样渲染功能,为了实现这个功能,需要解决两个问题:
- 贴图数据在内存的存储消耗
- 数据传输的带宽消耗
目前对于这两个问题的主要解决方案是采用贴图压缩的方式来降低各种消耗,而一个好的压缩算法需要满足以下四点:
- 较高的解码速度
- 编码结果可以实现随机读取
- 高保真,高压缩率
- 较高的编码速度
对于常见的各种压缩贴图格式如JPG等,其主要的缺陷是不能实现在压缩状态的直接随机读取,需要将数据完整的解压缩到内存中之后,才能完成数据读取。同样,一些‘变换编码’压缩算法如离散余弦变换DCT由于解码速度慢,同时偶尔也会导致一些解码结果的偏差如在尖角边缘产生环状纹路等(这种情况在贴图中含有直线或者文字类型要素时比较明显)
使用的最频繁的贴图压缩算法,应该要数调色板式的索引压缩方法了,这种方法属于vector quantisation(VQ)的一种,简单来说,就是用几个bit来表示一个像素,这个bit存储的是一个索引值,用来表示某个lut上像素的位置,DXT系列的贴图采用的就是这类压缩算法。这类调色板压缩算法存在一些缺陷:
- 解压缩算法需要重定位数据访问,即根据索引指向来读取对应的数据结果,在这个过程中需要涉及到两次数据读取,第一次是索引,第二次是索引指向的数据,从而导致访问速度的降低,同时由于由于多个像素可能共用一张lut,会导致内存数据访问的竞争,这种情况在多个数据访问同时发生的时候尤为严重
- 这类算法对于平常的filtering过程是不支持的,因为索引插值得到的结果可能是错误的,而且调色板插值将导致原有的索引系统完全崩溃,而如果只对索引进行插值,而调色板维持不变,将会导致贴图放大后的结果呈现块状表现。
- 压缩率低。
上图给出了几种主流的贴图格式以及对应的尺寸占用,这里是图片来源。
目前移动端上的主流贴图压缩算法主要包含了以下几种:
- PVRTC系列
- PVRTC
- PVRTC2
- ASTC
- ETC系列
- ETC1
- ATITC
- S3TC(也即DirectX TC系列)
虽然常用的贴图格式如PNG/JPG具有比上述压缩算法高得多的压缩率与还原质量,但是由于这些贴图的压缩率指的是在硬盘上的存储数据量,在内存中需要全部重新展开,而展开后的数据量并没有减少,对于没有显卡硬件支持的情况下,用压缩格式保存纹理没什么意义,特别是对于手持移动设备来说,解码象JPG这种复杂格式对电量的消耗是很大的,从而此处不再将这类压缩算法纳入考量。下面将针对上述这些算法的表现做进一步的叙述
PVRTC - Power VR Texture Compression
顾名思义,这个压缩格式是Imagination公司专门为PowerVR显卡系列开发的图形压缩格式,这种格式可以避免block-based压缩方法如ETC1等导致的矩形区域的不连贯。block-based压缩方法将贴图看成多个独立的block,并对各个block分别进行压缩,而PVR采用的策略则是用两张低分辨率的贴图来表征原来的贴图,在实际使用的时候,将这两张贴图分别进行上采样恢复到原贴图分辨率尺寸,之后进行混合得到一张全分辨率低精度的调制结果。
PVRTC实现的基本思路是采用两张或者多张低分辨率贴图(通常1/4或者1/8大小)与一张高分辨率低精度(通常2bpp)的调试贴图,实现对原贴图的模拟。因为低分辨率贴图的低频信息,可以得到如下的优势:
- 最终还原解压缩得到的贴图数据不会出现block-based压缩算法而出现的块状不连续问题;
- 解压缩过程速度快,这是因为解码时采用的是固定速率的(fixed-rate)调制方式,而不需要涉及到重定位数据访问(inidirect data access)
PVRTC的基本算法实现:
对原始数据进行一次低通滤波(基于linear wavelet transform),取得低频系数,并进行一次4x4的upscale上采样
将原始贴图数据与变换后的贴图数据做差,得到delta数据
对delta贴图进行axis分析,计算得到每个像素对应的principal axis vector,并对此vector进行flip,使得与neighbor的vector保持一致(这根轴跟原贴图的轴是不同的,而且基本上可以看成是近似垂直的)
将axis vector数据贴图进行filter之后,将vector与delta数据做点乘,根据结果的符号判断此时应该取用原贴图对应位置的像素颜色还是取用滤波后的贴图颜色数值减去delta颜色数值,从而得到全分辨率的初始低通贴图A或者B,
之后通过循环调优的方式来优化结果:简单来说就是根据一定的规则设置合适的modulation的数值,并根据调制后的数据结果与原贴图数据偏差计算新版的低通贴图A或者B,并重复上述步骤
其解压过程示意图如下(按照这种示意图,S3TC可以理解为这种压缩算法的一个变种,只要将调制信号改成1bit,true/false用来判断使用哪个贴图的结果作为最终的结果):
将低分辨率贴图上采样4x4之后,得到模糊的原分辨率贴图
跟据调制信号对多张贴图的采样结果进行插值混合,并将结果输出
PVRTC提供了两种压缩模式,分别是8:1的4bpp(4 byte/pixel)模式与16:1的2bpp模式,并且PVR同时支持RGB与RGBA的数据压缩格式,而即使使用的是RGBA压缩格式,也只是对有需要的alpha数据进行存储,对于没有必要的alpha数据,只存储了RGB数据,极大的避免了浪费。
PVRTC - 4bpp,压缩数据包含了M/4 × N/4个block(M,N是原贴图的尺寸大小),每个block包含了2个color数据(来源于之前提到的两张低分辨率贴图,如果是多张,那么此处将有多个),1个mode bit(指明是否具有alpha?),以及用来给4x4个像素做插值的调试数据。对于这种数据格式而言,每个block都可以有独立的alpha标志,据此可以进行不同的解码得到不同精度和结果的数据,如具有alpha的,精度会有所降低。
为了增加硬件层的数据重用,低分辨率贴图的颜色数据在初始化的时候编码被扩展成ARGB4555(原来是1位表征alpha),对于不透明物件来说前面4位数值为0xF,而对于透明/半透物件来说,第一位为0,后续三位用来表征透明程度。为了降低硬件消耗,接下来先使用线性插值完成上采样,之后再将结果转换到ARGB8,而不是反过来,而这种顺序的颠倒是不影响结果的(因为转换只是做了一个与常数的乘法,而这个乘法可以移到外面)。
32bit的调试数据可以分割成16个2bpp数据,每个数据可以表示四个数值,根据modulation mode的不同可以对应于不同的数值:
默认标准Mod Mode为0,则此时00,01,10,11分别对应0/8,3/8, 5/8,8/8四个数值,用以对两张color贴图的value进行混合。设置这四个参数的原因有两方面的考虑:
权重数值简单,实现起来方便
一般认为调试参数的分布通常与normal distribution的形状保持一致,所以考虑将这些数据稍微向着中心倾斜?
如果Mod Mode为1,则此时对应的是0/8,4/8,4/8,8/8四个数值。在这种情况下有一个特殊处理的case,就是当modulation数值为10的时候,此时会强制alpha为0,虽然如S3TC那样设置punch through texels为black是很常见的,但是这样会导致在filtering的时候物件边缘处出现不想要的halos(光晕,漏光?),所以,为了避开这个问题,通过设置alpha为0来只选择两个低分辨率贴图color的其中一个作为最终输出结果。
Imagination公司推出的升级版PVRTC算法PVRTC2压缩模式依然分为4bpp与2bpp两种,但是压缩质量有所提升。
PVRTC的优势与不足:
优点:
支持RGBA
根据需要,有4bpp与2bpp两种不同压缩率的压缩选项
在PowerVR硬件设备上有优化加成
不足:
只有PowerVR硬件才能支持?
只有2的幂次方尺寸的正方形贴图才有比较好的表现兼容性?
压缩速度较慢
压缩带alpha贴图效果很差
S3TC是一种block-based的压缩算法,这种算法也有另外一种称呼DXTC,这是PC时代使用最广泛的贴图压缩算法,其与其他块状压缩算法的区别在于,每个4x4色块通常具有一个主轴(其实就是颜色变化方向),这样围绕这个主轴,就可以假设所有的像素都落在这条主轴附近,从而只需要根据主轴两个端点的颜色做线性插值得到其他颜色数据,所以可以得到相较于其他块状压缩算法更高的压缩率。
这种算法在每个色块中的信噪比是恒定的(压缩率也是固定的)。且大的颜色误差容易出现在颜色变化剧烈的区域以及块状边缘。
S3TC有5种不同的压缩算法,对应于DXT1~DXT5,不过一般只有DXT1,DXT3,DXT5得到的应用比较广泛。
- DXT1:这是S3TC中具有最高压缩率的压缩方式,这种压缩算法可以将16个像素组成的一个block压缩成一个64bit的数据,这个64bit的数据由2个不同的16bit颜色数据(565)以及4x4个2bit的索引数据组成。
DXT1可以表示不透或者完全透明的贴图数据,当color_0数据比color_1大,那么此时贴图表示的数据是不透明的,否则则带有一位透明标志。16个2位索引则表明了这4×4个像素块所在像素的颜色值,2位可以表示4种状态,这4种状态对应于color_0,color_1以及在不透情况下通过均匀插值计算得到的color_2和color_3,在透明情况下,插值得到的color_2,而color_3用来表示透明。
将16个像素组成的block压缩成一个128bit的数据,其中64bit用来存储alpha数据(前面64bit),而另外64bit用来如DXT1一样表示color数据(后面64bit)
DXT2与DXT3中存储的alpha数据是直接的16个4bit alpha数据,不需要如DXT1中的颜色数据一般另作间接索引
DXT2:DXT2中的颜色数据已经完成了Premultiplied by alpha操作,即在color_0与color_1中存储的数据是已经进行了alpha加成处理的?在后续使用时如果alpha发生变化,只需要改变这两个颜色的数值,不需要再单独复合。。。
-
DXT3:其中的颜色数据与alpha数据是单独存储的,没有所谓的混合,等使用的时候需要取出来参与计算
DXT4与DXT5中的alpha数据则是如DXT1中的颜色数据一样,需要另外索引得到,不同的是,64bit数据被分割成2个8bit的alpha数据,和16个3bit的索引数据,可以表示8种不同透明层度。跟DXT1一样,根据alpha_0与alpha_1的大小关系,有不同的编码实现,当alpha_0>alpha_1时,对alpha_0与alpha_1进行插值,得到6个中间值;否则对alpha_0与alpha_1进行插值,得到4个中间值,而剩下的alpha_6与alpha_7分别赋值0与255.
DXT4:颜色数据已经完成了Premultiplied by alpha操作
DXT5:与DXT3相同,颜色与alpha独立
优点:
压缩速度与解压速度不慢
有广泛的平台支持
缺点:
- 并不是所有的android都能支持
ETC - Ericsson Texture Compression
ETC是Khronos专门为ES2.0设计的贴图压缩格式,其算法与S3TC一样,都是block-based的,目前ETC有两种版本:ETC1与ETC2。其基本原理给出如下:
首先制定某个block(2x4)的基色(base color),如下图中的蓝色圆圈所示
由于人眼对于亮度luminance的敏感度高于色度chrominance的敏感度,所以ETC将按照luminance的主轴方向对各个像素进行编码
- 编码完成后的结果如下图所示,在需要的时候将block-basecolor与pixel-luminance结合,就可以得到解码结果:
在各个block中的各个像素的luminance分布接近一条直线的时候,这种方法可以得到比较好的解码质量,但是如果各个像素的luminance分布比较散乱,结果就会比较糟糕了,此外,如果某个block落在两个颜色中间,而这个block中的像素luminance都是比较接近的,那么经过编码解码得到的block就会偏向于某种颜色,从而出现过渡区域的块状锯齿。
ETC1是OpenGL ES的标准,但是不是OpenGL ES2.0的标准,所以在OpenGL ES2.0中需要检查是否支持ETC1,ETC1支持对24位RGB贴图的压缩,但是不支持对带有alpha通道的贴图的压缩,4bpp,也不支持单独的R通道或者RG通道贴图压缩;
ETC2是ES3标准里的格式,具有与ETC1相同的属性与压缩率,但是拥有更高的质量(Peak Signal to Noise Ratio:1.0db better than ETC1, 0.8db better than S3TC, 1.6db better than PVRTC),且对alpha贴图支持比较好,提供了类似DXT3与DXT5的完整alpha支持的8bpp压缩模式与1bit alpha的4bpp压缩模式,此外还提供了EAC格式,可以支持对单个通道或者两个通道R/RG的数据压缩。其缺点在于压缩工具的压缩速率过低。
ETC2是向下兼容的,即可以使用加载ETC2的方式加载一张ETC1的贴图,且可以正确解码,另外可以将ETC1与ETC2贴图存储在一张贴图文件中(参考文献)。
ETC2有多个模式:
- T Mode:适用于具有两种不同chrominance堆的情况,每个block存储两个基色,并根据第一个颜色沿着luminance intensity direction方向计算出额外的两个颜色值,如下图所示:
- H Mode: 适用于具有两组luminance intensity分布的情况,如下图所示,最终分别存储两个基色数值,之后对这两个基色按照intensity方向进行调制,最终的四个颜色值被用来解码,还原原始图像:
跟T Mode一样,H Mode需要59bits,但是不同的是,这59bits中只有58bits是有效的,剩余一位用作标志,0表示第一个颜色是最暗的颜色,1表示第一个颜色是最亮的颜色。
- Planar Mode:对于一些颜色变化不明显的block,使用ETC或者S3TC的方式是不适合的,这种情况可以使用planar mode来存储数据,如下图所示,每个block存储3个RGB676的颜色,最终的解码使用插值得到(三个颜色奠定两个坐标轴)
ETC下有两种贴图格式,KTX与PKM:
KTX是标准的Khronos压缩格式,这种格式的容器可以同时容纳多张贴图纹理数据,当使用KTX存储Mipmap数据时,只需要一张KTX就可以实现多级Mipmap数据的存储。
相对于KTX的灵活与大容量而言,PKM是一种比较简单的贴图格式,只能容纳一张压缩贴图数据,用这种格式存储mipmap的时候,将会创建多张贴图用以完成数据存储,这种方式效率较低,所以,如果使用mipmap,必须要考虑使用KTX
优势:
相对于PNG来说,贴图数据量有所减少
所有的android设备都能兼容
劣势:
贴图质量有所损失
ETC1不支持alpha数据压缩
ETC2压缩速度慢
ASTC - Adaptive Scalable Texture Compression
ASTC是block-based的压缩实现算法,每个block占用128bit,但是与S3TC不同的是,不同压缩格式下,每个block表示的像素块大小是可以伸缩的,支持使用不同的ASTC压缩率对贴图进行压缩,范围从4x4(8bpp)到12x12(0.89bpp)不等,而且,对于每个block,都可以有自己的编码方式与权重(此外,对于block的尺寸也不仅限于POT,比如可以是6x5的(这种情况会为像素到block的归属查询增加一些困难,不过由于所有block的尺寸都可以总结为3,5以及POT的乘法结果,按照这个结论进行计算,也不会再增加太多麻烦[6]),而每个block压缩后的数据长度是128bits,因此对于同一种压缩格式下,虽然各个block会采用不同的压缩策略,但是最终的压缩率都是相同的),所以可以根据贴图数据进行自适应压缩。通常采用6x6(3.56bpp)一档的压缩策略,压缩质量高过PVRTC 4bpp。
虽然block尺寸越大,贴图压缩率越高,但是过高的block尺寸也会有问题,抛开因此导致的质量下降不提,大尺寸的block在带宽的消耗上回比小尺寸block要高,因为在读取某个像素的数据的时候会需要将整个block数据读取进来进行解码,带来了一定程度的浪费,这在使用过程中需要有所考虑[6]。
每个block的前6个bits用于指定block模式,不同模式对应不同的权重数目(以及这些权重所能取用的数值范围),高比特率压缩模式(block包含颜色比较复杂时)可以为每个像素指定一个权重,比如8x8 block模式下,有两种支持64个权重的压缩模式,其中一种模式的权重用于在两种颜色中进行选择(只需要一个bit),另外一种模式则支持在3中颜色中进行选择(需要1.6个bits)。低比特率压缩模式(颜色比较一致的)block中,可以指定少一点的权重数目,比如8x8 block模式下,总共有六种不同的权重压缩模式,这六种压缩模式都包含12个权重值,分别对应2,3,4,5,8,16种颜色选择。在这种稀疏权重编码模式下,每个权重会对应到特定的像素上,其余没有对应权重的像素则需要从前后两个具有权重的像素中插值出对应的权重。
与DXTC一样,每个block都包含两个插值端点(end points),但是不同的是,插值端点可能不一定包含所有的通道(RGBA),可能只包含其中部分通道(比如RG),这样就可以实现对不同格式的贴图进行不同的压缩(比如法线贴图,alpha贴图等)模式以得到更好的压缩质量。
对于端点而言,也并不只是只有一种编码方式[6],其编码方式主要有三种:
- independent,直接存储两个端点的颜色数值A,B,这种是最简单的编码模式,解压的时候使用Aweight+B(1-weight)方式进行
- base+offset,对于一些数值比较大的情况,直接存储两个端点颜色,精度可能不太够,此时可能会采用在base上使用较大的位数进行存储,在offset上分配较少位数,之后解压缩的时候,使用base+weight*offset的方式得到数值
- base+scale,对于一些颜色分布在luminance轴线上的情况,可以通过将颜色编码成(R, G, B, s),s表示的是颜色的scale,在解码的时候只需要使用s * weight * (R, G, B)即可
根据端点表达所需要的数值数目不同,可以分为如下的四种情况,每种情况各对应四种编码模式[6]:
- 2-values
- 4-values
- 6-values
- 8-values
每种模式都有各自的编码特点,比如部分模式在编码的时候对于一些通道会有一些特殊照顾,为这些通道分配更多的位数等,具体细节请参考文献[6]。
对于每个block中的像素,会存储其相对于端点的插值权重(weight),不过这里需要注意的是,插值权重的数目跟block像素的数目可能不是一一对应的,尤其是对于一些比较大的block而言,存储的权重是稀疏的,在使用前会需要对权重进行一次插值,计算出当前像素的权重,之后再使用这个权重插值出对应的color或者其他数据。
对于block中颜色分布比较复杂的情况,ASTC还会先对block的颜色进行分析,将block拆分成多个sub-block(最多四个[3],sub-block的数目会由一个2bits的区域指定,如果指定的sub-block数目超过1的话,那么就需要额外的10个bits用于指定划分模式索引(partition pattern index),划分模式索引用于描述每个像素对应的sub-block的索引(参考下面的示意图),实际存储的时候不会为每个像素分配两个bits用于说明划分模式索引,每个划分模式是通过hash函数生成的,其输入是相应像素的uv坐标以及sub-block的索引),之后每个sub-block当成一个block进行处理,在解压的时候会先定位当前像素对应的sub-block,之后在sub-block的基础上进行数据还原,这里需要注意的是每个sub-block都会保存自己独立的端点数据(也有着自己的压缩策略,比如某个sub-block支持LDR,而另一个则支持HDR等[6],不过这种多样性是有限制的,出于抑制不常用搭配从而减少用于描述color-mode的位数的考虑,这里限制相同block中的不同sub-block的color mode在断点颜色数值数目差异不能超过4,比如只支持2-values与4-values,4-values与6-values,不支持2-values到6-values等的搭配[6]),但是其使用的权重数据在各个sub-block中是共享的[3](共享权重有什么意义?)。
对于一些各通道数据关联性比较差的情况(比如RGBA分别存储的是完全不同的四张贴图),ASTC还支持为每个通道分配一套完全不同的权重(端点数据本身就是不同的,无需额外处理),这样可以保证不同通道的插值结果侧重点不一样[3]。
block中的数据存储采用的是Bounded Integer Sequence Encoding(BISE)的方式进行的,以尽可能的节省存储空间,而这就是ASTC算法的核心[1]:
对于一个block中包含5个权重值,比如0, 0.25, 0.5, 0.75, 1.0,我们可以用整数0~4来表示从而压缩权重的浮点存储空间。
对于每个整数,按照传统方法,需要分配3个bits,但是会有三个数值是浪费的(5, 6, 7),对于不同的最大值,浪费的幅度也不同,具体参考下图,只有5个数值是有效的,而对于三个这样的group(难道每个group都是0~4?需要额外的映射表,见下面的映射表部分),可能就是5^3 = 125个有效数值,这个比较接近2^7 = 128,因此如果我们有办法将这三个group合并到一起进行编码,就能很好的解决3个数值的浪费问题,这样原来3个group中每个像素3个bits,三个像素9个bits就可以直接使用7个bits来代替了,这个以5位基数的编码(为什么要以5为基数?如果建立一个映射表的话,15个数值只需要4个bits就可以了啊?因为这个映射表是全局的,包含了0~124的所有可能数值)模式称之为基于5的BISE压缩;
映射表[2]:map_quints_to_integer[0][4][3] = 23
map_quints_to_integer[5][5][5] = {
{
{0, 1, 2, 3, 4,},
{5, 6, 7, 8, 9,},
{10, 11, 12, 13, 14,},
{15, 16, 17, 18, 19,},
{20, 21, 22, 23, 24,},
},
...
... // Skipped some portion
...
{
{101, 102, 103, 104, 105},
{106, 107, 108, 109, 110},
{111, 112, 113, 114, 115},
{116, 117, 118, 119, 120},
{121, 122, 123, 124, 125},
},
};
同理,对于每个group包含3个数值的情况而言,就可以用基于3的BISE压缩,将5个group放到一起进行编码,每个group一个像素只需要8个bits<2*5 = 10bits。
对于group的候选数值不是3,也不是5的时候虽然也可以按照BISE的方式进行编码,但是其浪费的幅度可能稍微多一点。
BISE可以将整数编码分别拆分成如下三种情况:
- 如果N <= 2^n - 1(0,1,3,7,15,31...),N-1二进制的最高3位为11x,因为这种情况下N已经接近于2^n,可以直接使用n个bits来对整数进行编码,S个整数只需要S*n bits就可以存储
- 如果N <= 3 * 2^n - 1( 2,5,11,23,47,95...),N-1二进制的最高3位为101,将前面2个bits抽出来(取值范围0~2,不可能出现11的情况)使用前面基于3的BISE编码(即对于2^n 前的系数使用一个trit编码,5个group共同编码,每个数值占用8/5bits),剩下的部分按照2^n编码,使用nS + ceiling(8S/5) bits就可以存储
- 如果N <= 5 * 2^n - 1(4,9,19,39,79,159...),N-1二进制的最高3位为100,将前面3个bits抽出来(取值范围0~4)使用前面基于5的BISE编码(即对于2^n 前的系数使用一个quint编码,3个group共同编码,每个数值占用7/3bits),剩下的部分按照2^n编码,使用nS + ceiling(7S/3) bits就可以存储
举个例子,假如N=12,N-1的最高三位为101,因此可以用一个trit(公式中的t表示的是最高两位)以及两个bits来表示,用公式来描述,就是
如果N=40,N-1最高三位为100,因此可以表示成3个bits+一个quint(公式中的q,表示的最高三位):
经过BISE编码之后的空间浪费与编码之前的空间浪费比较见下图:
下面给出ASTC压缩格式使用时的一些建议[5]:
- 由于ASTC提供了众多不同的压缩模式,每个压缩模式的压缩率都各不相同,虽然使用起来比较灵活,但是在把控上可能会需要花点心思,这里为了方便说明,列出此前其他压缩方法的一些基本特征,用于与ASTC压缩模式进行比对:
上图中颜色格式中带有+号的,指的是贴图中存了两块无关数据的情况,比如RGB+A,表示A通道与RGB通道的数据完全无关联,这种模式下,当A通道数据与RGB通道数据无关时,能够得到很好的压缩质量,但是当他们本身是关联时,按照这种模式压缩得到的质量就比不过完全当成关联数据来压缩质量好。
由于ASTC解压后的数据肯定会被用于填满四个通道的,因此对于那些原始贴图中占用的通道小于4个的情况要怎么处理会比较困惑,实际上压缩后的数据是可以根据需要只占用1个或者多个通道的(每个block可以单独设置),而性价比最高的方案就是在保证质量的前提下尽量少的占用压缩后的数据通道,这里有两个特例需要说明:
- ASTC提供了一种将RGB通道编码成一个luminance数据的方法,因此只需要占用一个通道即可
- ASTC提供了一个将alpha默认看成1.0的压缩方法,在特定的情况下,就可以省掉alpha通道的空间占用
在使用的时候,建议根据输入贴图的格式来调整压缩的方案。
根据上面的两个特例,上图给出了四种建议的压缩方法,分别对应RGB是否要用单个luminance进行存储以及alpha是否可以用1.0替代等四种情况。coding swizzle指的是压缩编码时数据的存放布局,比如L+1情况下rrr1表示的是将luminance存储到r通道(RGB压缩成一个通道),alpha不占用额外空间;sampling swizzle指的是贴图采样的时候建议的使用方式,之所以使用.g而不使用.r是因为考虑到与其他的压缩格式比如BC1/ETC等的兼容,避免不同的压缩格式下,需要两套不同的shader代码,并不是因为g通道有什么特殊的能力,同样.ga也是一样的道理。
有了前面的铺垫,我们就可以参考下面这张图来对比其他压缩模式与ASTC压缩模式了:
此外,这里还有两点需要注意:
- 关于sRGB,由于sRGB可以存储更多人眼所需要的信息,因此对于颜色等数据,尽量使用sRGB进行压缩,不过需要注意的是,sRGB只针对RGB三通道,对于alpha通道而言,还是采用线性编码存储的
- 关于HDR,ASTC对于HDR格式的贴图有两种压缩模式,第一种是将RGB看成是HDR(超出[0.0, 1.0]范围)的,但是Alpha还是LDR的;第二种则是将RGBA四个通道都看成是HDR的,各位在实际使用中可以根据实际情况进行选择。
质量对比
先看看压缩后的贴图与原贴图的方差对比:
BaseColor
pvrtc/etc2的压缩质量介于astc 8×8和astc 10×8之间。
Normalmap
pvrtc压缩质量介于astc 6×6和astc 8×5之间。 etc2压缩质量介于astc 8×8和astc 10×8之间。
带alpha贴图(lightmap)
pvrtc压缩质量介于astc 8×8和astc 10×8之间。 etc2压缩质量介于astc 5×4和astc 6×5之间。
参考文献
[1]. ARM Unveils Details of ASTC Texture Compression at HPG Conference
[2]. FLEXIBLE TEXTURE COMPRESSION USING BOUNDED INTEGER SEQUENCE ENCODING
[3].High quality RGBM texture compression with ASTC
[4]. Adaptive Scalable Texture Compression
[5]. Effective ASTC Encoding
[6].Adaptive Scalable Texture Compression