MelonTeam 移动终端前沿技术的探索者

纹理压缩

2017-07-21
yockieyang

导语 我们经常听说有相应的jpg,webpp,png等图像压缩格式,但你有没有听说过ETC,S3TC等格式吗?如果没听说就请看我这篇文章吧。

一、前言
游戏场景里,贴图是影响真实性的重要因素。通常贴图越大,也就越精细,但其占用的内存空间也就更大。

常用的图片文件格式有:BMP, TGA, JPG, GIF, PNG等。
不过,像JPG这种常见的图片压缩格式,对于多数应用的内存占用和显示总线带宽占用并没有带来直接的好处,因为还得对JPG进行解压缩成原始的像素,再传给显卡,而且还有加载时的解码计算负担。这是因为显卡的纹理解码硬件不理解JPG格式。所以,在没有显卡硬件支持的情况下,用压缩格式保存纹理没有什么意义,特别是对于移动设备来说,解码像JPG这种复杂格式是很浪费电的。
常用的纹理格式有:RGB_565, ARGB_4444, ARGB_1555, RGB_888, ARGB_8888等。
不论何种图片文件格式,它们都是为了存储像素信息而是用的对信息的特殊编码方式,它存储在磁盘中,或者内存中,但是并不能被GPU所识别,因为以向量计算见长的GPU对这些复杂的计算无能为力。当这些文件格式被游戏读入后,需要经过CPU解压成RGB_565,ARGB_4444, ARGB_1555, RGB_888, ARGB_8888等像素格式,才能传送到GPU里使用。纹理格式是能被GPU所识别的像素格式,能被快速的寻址并采样。
纹理格式如:RGB_565,每个像素占用:5+6+5=16 (bits),共 2 个字节。RGB_888,每个像素占 24 位,3 个字节。ARGB_8888占 32 位,4 个字节。
关于纹理格式的更多资料:http://en.wikipedia.org/wiki/High_color

二、贴图压缩方式
对于一张 512_512 的纹理,RGB_565格式的文件占用 512 KB的容量。
计算公式为:numBytes = width _ height _ bitsPerPixel / 8
ARGB_8888格式的文件需要占用1M的容量;如果是1024_1024,则需要更多。
現在一般的显卡上通常有 32MB 的显存容量。如果每个贴图都要 2MB 的話,即使不计 frame buffer 所占用的空間,也只能使用 16 张贴图。这显然是不可接受的。所以,现在的游戏通常无法使用很大的贴图。
然而,在储存一般的影像的時候,通常会使用某些压缩方式。现在常见的 JPEG 压缩,可以达到 1:6 甚至 1:12 的压缩比。如果把类似的压缩方式应用在贴图上,不就可以大量减少贴图所用的空间了吗?
不幸的是,一般的影像压缩方式,是沒有办法用在贴图上面的。因为,显示芯片在存取贴图时,是一种「随机存取」的动作。也就是说,显示芯片通常会需要以任意 的顺序存取贴图里的资料。一般的压缩方式如 JPEG,都利用了 variable length 的 coding,简单的说,它们必需以一定的顺序才能解开。因此,不能用这种方式来压缩贴图。
一种压缩方式,是改变颜色空间。例如,3dfx 的 YAB 格式,就是一种不同的颜色空间。利用 YAB,每个像素只需要 8 bits,就可以达到接近 16 bits 的效果。不过,无论如何,这样都使颜色的数目减少。因此,整个贴图的色彩变化就受到了限制。
另一种方式,就是用传统的「调色盘」结构。利用一个 256 种颜色的调色盘,就可以把贴图以 8 bits 的方式储存。不过,虽然它的色彩空间较大(可以是 24 bits 或 32 bits),但是总颜色数目还是不能超过 256 种。所以,它的应用范围仍然有限。
现在常用的贴图压缩方式,则是利用以区块为基础的方式。通常的做法是,把贴图切割成许多小区块,再对各个区块进行压缩。例如,S3TC 就是把贴图切成 4x4 的小区块。利用这种做法,就可以对区块进行某种处理(通常就是 vector quantization 或是其变形),显示芯片也可以以区块为单位,进行随机的存取动作。因此,这是适合用在贴图的方式。
不过,区块的大小会影响到压缩的效果。一般来说,区块越大,就能有越高的压缩比。不过,越大的区块也会使额外的负担增加。因为显示芯片只能以区块为单位来读取贴图,如果区块越大,则每个区块中就可能会有越多的资料是不需要的。所以,也不能任意把区块的大小加大
在Beers,Agrawala和Chaddha于1996年发表的一篇影响深远的论文基於已壓縮紋理的渲染 [1]中,他们列举四项纹理压缩的特点,使其不同于其他图片压缩技术。
解压速度:为了尽可能不影响性能,解压缩要尽可能快,最好能直接从已压缩的纹理直接渲染。(所谓解压,就是把贴图转换成GPU能识别的纹理格式:RGB_565等。)
随机访问:由于几乎不可能预测纹理像素被访问的顺序,任何纹理压缩算反必须允许对其中的纹理的随机访问。所以几乎所有的纹理压缩算法都已块为单位压缩和存储纹理像素,当某一个纹理像素被访问时,只有同一块中的若干纹理像素被读取和解压缩。这项需求也排除了很多压缩率较高的图片压缩格式,例如:JPEG和行程長度編碼。
压缩率和图像质量:由于人眼的不精确性,相比于其他应用领域,图像渲染更适宜使用有损压缩。
编码速度:纹理压缩对压缩速度的要求不高,因为绝大多数情况下,纹理只需要进行一次压缩。(但是对解压速度要求较高。)
由于其数据访问模式是事先知道的,纹理压缩常作为整个渲染管线的一部分,在绘制时动态的对已压缩数据进行解压缩(可以把解压缩放在shader里处理)。而反过来渲染管线也可以通过纹理压缩技术来降低对显卡位宽和存储的需求。在纹理贴图中,已经压缩的纹理和没有经过压缩的纹理使用起来基本没有区别,都可以被用来存储颜色数据或其他数据,例如凹凸贴图或法线贴图,也都可以和Mipmapping或各项异性过滤等共同使用。
主流的纹理压缩标准:ETC, PVRTC, S3TC。


说一说

目录