虚拟贴图理论之贴图压缩

虚拟贴图无论对内存带宽还是显存带宽,都造成了巨大的压力,因此我们需要使用压缩格式的文件。从工程的角度来说我们需要了解各种压缩算法的压缩比,压缩效果,以及编码译码的速度,从而选择最佳方案。为了能够更好的使用压缩格式,我这里简单的了解了三种压缩格式,分别是代表贴图压缩的jpg格式,代表纹理压缩的dxt格式,以及代表通用压缩的zip格式。在讨论这三个压缩格式之前,我们先了一下常见的底层压缩算法。

RLE压缩算法

比如下面的文本信息“[data][data][data]",假定上述文本使用的是ASCII码,那么上面的字符串占用了12个字节的内存(不考虑[])。我们第一个想法就是将重复的信息用一种编码表示,比如[5][data]。其中一个字节代表块重复的次数,另一个字节代表重复的内容。这种压缩算法就是RLE压缩算法。

LZ77算法

如上图红黑两条竖线代表一个窗口,这个窗口不停的向前移动,算法的目的就是找到后面的字符与窗口中重复的字符串,然后按照(偏移起始地址,偏移量)的方式存储信息。

哈夫曼编码

上面的LZ77算法我们用(偏移起始地址,偏移量)存储文件信息。假如偏移地址有1,2,3,4。我们如何编码去存储这些数字呢?如果用定长编码去存储,肯定会浪费空间,我们希望使用变长编码,变长编码需要满足两个条件:

1.出现频率最高的数字,使用的编码越少

2.每一个编码都是前缀无歧义编码,也就说任意一个编码不能是其他编码的前缀

哈夫曼树刚好满足这两个条件,因此根据编码出现的频率生成一棵哈夫曼树,然后对其进行编码就形成了哈夫曼编码。比如A,B,C,D,E,F出现的次数分别是2,3,7,9,18,25,最后生成的哈夫曼树如下图:

JPEG图片压缩原理概述

上面讲的都是常见的压缩算法,它们都是无损的,如果想要深入的了解这方面的知识可以参考《Data Compression The Complete Reference》这本书,里面很详细的介绍了各种压缩算法。并不是所有资源都可以进行有损压缩,比如游戏安装包,小说等等。但是对于贴图我们是可以牺牲一些图片质量为文件瘦身。JPEG 压缩是有损压缩,但这个损失的部分是人的视觉不容易察觉到的部分,它充分利用了人眼对计算机色彩中的高频信息部分不敏感的特点,来大大节省了需要处理的数据信息。

1.色度抽样-有损

通常我们游戏中使用的色彩空间是RGB,除了RGB色彩空间还有很多色彩空间比如YUV,YCbCr,YCoCg,这些色彩空间都可以和RGB空间进行无损转换。为什么会有这么多的色彩空间呢?存在即合理,它们的存在是有一定的历史原因的。比如YUV空间是为了同时支持黑白电视以及彩色电视。YUV空间将颜色分成亮度信号Y以及色度信号U和V。Y就是我们常用的亮度图,黑白电视就使用Y进行解析。JPEG使用YCbCr空间进行压缩,因为人眼睛中分为两种细胞,柱状细胞以及椎状细胞,柱状细胞分管亮度,椎状细胞分管色彩,而柱状细胞的数量是椎状细胞的20倍,也就是说人的眼睛对亮度信息特别敏感,而对色彩信息不敏感。这也是为什么一个游戏效果的好坏要看光影表现。JPEG使用YCbCr空间,可以保留信号Y而对信号CbCr进行降采样,比如按照4:2:0,4:2:2,4:1:1等等,如下图:

JPEG格式的第一步压缩就是色度抽样,比如YUV 4:2:0的码流为:

Y0 U0 Y1 Y2 U1 Y3

Y4 V0 Y5 Y6 V1 Y7

映射成8个像素为:

[Y0 U0 V0] [Y1 U0 V0] [Y2 U1 V1] [Y3 U1 V1] 

[Y4 U0 V0] [Y5 U0 V0] [Y6 U1 V1] [Y7 U1 V1]

可以看到压缩比为4:1,因为丢失了UV信号所以是有损压缩。

2.离散余弦变化(DCT)- 无损

为了获取高频信息,我们需要将色彩域转换到频域上,而这个转换方法用到的数学理论就是DCT(类似傅里叶变换)。首先图像被分成了8*8的像素组,每个像素组可以被 8*8 个余弦波精确表示。这64个余弦波,可以组合成任意 8*8 的图形。我们只要用系数对这64个余弦波进行加权,就可以表示出任何的图形。比如下图:

经过 DCT 转换后的频率系数矩阵分别对应64个余弦波在 8*8 图形中的权重。可以看出,左上部分低频区的系数比较大,右下高频区的系数较小。鉴于人眼对高频区的识别不敏感,所以在下面量化部分可以舍弃一些高频区的数据。这里的 DCT 变化还没开始压缩。

3.量化-有损

在 DCT 变化后,舍弃高频区数据的过程称为量化。有两份量化表可供选择,分别为亮度量化表和色度量化表:

上表分别为亮度量化表和色彩量化表,表示 50% 的图像质量。这两张表中的数据基于人眼对不同频率的敏感程度制定。

量化表是控制 JPEG 压缩比的关键,可以根据输出图片的质量来自定义量化表,通常自定义量化表与标准量化表呈比例关系,表中数字越大则质量越低,压缩率越高。PhotoShop 有12张量化表。

量化过程为,使用量化矩阵与前面得到的 DCT 矩阵逐项相除并取整。之前为亮度矩阵,顾使用亮度量化表:

量化是有损的,在解码时,反量化会乘回量化表的相应值。由于存在取整,低频段会有所损失,高频段的0字段则会被舍弃,最终导致图像质量降低。

4.熵编码(zigzag scan & 霍夫曼编码)- 无损

得到量化后的矩阵就要开始编码过程了,首先要把二维矩阵变为一维数组,这里采用了 zigzag 排列,将相似频率组在一起:

得出的序列我们可以使用RLE编码进行压缩,最后再使用哈夫曼编码进一步压缩,如下图:

至此,这个亮度 8*8 的像素组压缩编码完毕。以上步骤就是jpeg编码的大体步骤,在实际工程中通常我们会用第三方工具进行压缩和解压。jpeg的压缩率很高,可以大大降低磁盘IO读取的速度,但是它的解码太复杂,无法做为gpu支持的纹理格式,因此,我们在项目中还是要用cpu进行解码,然后读取数据生成纹理格式。在解压的时候不仅增加了cpu的开销,还增加了内存的使用量。而且对于显存的带宽没有任何优化作用。为此我们还需要了解一种gpu支持的纹理压缩格式比如dxt。

DXT纹理压缩

DXT纹理压缩格式之所以能被硬件支持,原因是它的原理非常简单,如下图:

DXT1格式的工作原理就是将贴图分成4*4的块,然后保留两个像素的颜色,另外再插值生成两个16位像素的颜色。然后用16个2bit的索引,索引这16个像素,就像顶点索引一样。DXT1的压缩率为16 * 16 / (16*2 + 2*16) = 4。

DXT1格式的图片质量损失还是挺严重的,主要是首先RGB24为被压缩成了16为,然后就是只选取两个像素,如果像素之间差距比较大,就会有明显的像素丢失,如下图:

通常这种情况发生在比较细的边界中,对于这种情况我们可以提高贴图的分辨率来提高贴图的质量,因为RGB对应DXT1的压缩比是6,可以适当的提高分辨率,增加贴图的质量。

DXT1支持1位的alpha test,如果color_0 > color_1代表不使用alpha通道,这种情况和上面的描述一致,如果color_0 < color_1,代表开启alphat test,之前的四个像素,变成了三个像素,索引里面的11代表透明的像素。

DXT2和DXT3中多了64位存储alpha值,每个像素分配4位,DXT2中颜色是已经完成了Premultiplied by alpha操作(已完成颜色与alpha的混合,当透明度发生改变时,直接改变整体颜色值,不必再单独复合),DXT3的Alpha信息则是相对独立的,之所以要区分开了则是为了适应不同的需要,因为有些场合需要独立的Alpha信息。

DXT4和DXT5也是用于表示具有复杂的透明信息的贴图,与2和3不同的是4和5的Alpha信息是通过线性插值计算所得,类似于DXT1的颜色信息。同样的,每4×4的像素块的透明信息占用64位,所不同的是,64位中采用了2个8位的alpha值和16个3位的索引值,既然每个像素的索引占3位,那么可以表示8种不同的透明状态。在这里插值的方法有两种,一种用于表示具有完全透明和完全不透明的状态,另一种则是仅在给出的极端值alpha_0和alpha_1中进行插值。区分的方法也是通过比较alpha_0和alpha_1的大小来实现的,如果alpha_0大于alpha_1,则通过插值计算剩下的6个中间alpha值;否则,只通过插值计算4个中间alpha值,alpha_6直接赋值0,alpha_7直接赋值255。DXT4和DXT5的区别同DXT2和DXT3的区别相同,DXT4的颜色值是理解为已经完成Premultiplied by alpha操作的。另外需要注意的是,所有的压缩纹理格式都是2的幂,因为纹理压缩的单位是4×4像素,所以如果贴图的大小为16×2或者8×1这样的比例,系统会同样采用4×4的单位进行压缩,会造成一定的空间浪费,同样的大小会被占用,只是不会参与使用而已。

为了提高压缩纹理的表现效果,我们可以使用YCoCg色彩空间配合DXT5的压缩格式,实现高质量的压缩纹理。我们使用DXT5的Alpha通道存储亮度(Y),用色彩通道存储色差信息。然后在ps中将YCoCg空间转换到RGB空间,YCoCg空间转换到RGB空间的算法非常高效只需要移位操作和加减操作。

ZIP压缩

zip压缩说简单也简单,说复杂也复杂,复杂在细节,简单是因为它底层使用的就是lz系列算法+哈夫曼编码的变种。我这里就不班门弄斧了。

总结

最优的压缩方案可能就是:

YCoCg空间+DXT5压缩+zip压缩

这一套组合拳即保证了磁盘IO,又保证了显存IO,还降低了内存和显存,而且还保证了质量。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值