HPP_Graphics_3.6 纹理压缩

a). 纹理压缩简介

  • 纹理压缩是为了解决内存带宽问题,专为在计算机图形渲染系统中存储纹理而使用的图像压缩技术;

a.1). 图片压缩 vs. 纹理压缩(为什么要纹理压缩)

  • 图片格式:JPG、PNG、GIF、BMP等;
  • 纹理压缩格式: ETC、DXT、ASTC等

图片压缩格式大部分都是整体依赖,即不支持像素随机访问(基于整张图片进行压缩,无法直接实现单个像素的解析),且图片压缩格式无法被GPU识别,还需要经CPU解压缩成非压缩纹理格式才能被识别。因此采用基于块压缩的纹理压缩,能够更快读取像素所属字节进行解压缩以支持随机访问

  • 纹理管线:

    TexturePipeline

b). 常见纹理压缩格式

常见纹理压缩格式

b.1). DXTC

DCTC纹理压缩格式来源于S3公司提出的S3TC算法,基本思想是把4×4的像素块压缩成一个64或128位的数据块,优点为创建了一个固定大小且独立的编码片段,没有共享查找表或其他依赖关系,简化了解码过程;

DXT00

b.1.1). DXT1(BC1)

适用于:不包含透明信息RGB、只包含1位透明信息的贴图(即透明或完全不透明)

  • 对与不包含透明信息的RGB

    • 每一块具有两个16位RGB颜色值(RGB565)$color_a、color_b$,代表了此4x4像素块中颜色极端值,然后通过线性插值计算出两个中间颜色值,16个2位索引值则表示每一个像素的颜色值索引。

    • 所以,对与4x4的像素块:

      • 2x16 RGB颜色值(RGB565)

      • 16x2 颜色索引值(索引2个颜色极端值+2个插值得到的中间值)

DXT1

  • 对与包含1位透明信息的纹理
    • 通过$color_a、color_b$ 插值出一个颜色中间值 $color_c$ ,并用 $color_d$ 表示透明/不透明,其每个像素通过2位索引这四个颜色
  • 压缩率:6:1

b.1.2). DXT2/DXT3 (BC2)

DXT2/3与DXT1类似,表示颜色信息的64位数据块不变,另外附加了64位数据来表示每个像素的Alpha信息,整个数据块变为了128位;;

每个像素占用8位,0-3表示透明信息,4-7表示颜色信息;

b.1.3). DXT4/DXT5 (BC3)

DXT4/5与DXT2/3的差异在于其Alpha信息是通过线性插值所得的,表示颜色信息的64位数据块依然不变,而Alpha信息则由2个8位Alpha极端值和16个3位索引值组成;

DXT5和DXT3分别计算RGB和A再混合,而DXT4和DXT2先混合RGBA,若A改变也不再重新混合而是直接改变整体颜色

b.1.4). DXTnm

Unity内贴图类型选为法线后会采用DXTnm压缩格式,该格式会把法线贴图R通道存入A通道,然后RB通道清除为1,这样可以将法线XY信息分别存入到RGB/A中分别压缩,以获得更高的精度,然后再根据XY构建出Z通道数据;

即将法线贴图RGBA变为AG通道;

AG

b.2). ATI1/2

b.2.1). ATI1(BC4, 4x4 4位)

ATI1为ATI公司开发的纹理压缩格式,也被称为BC4,其每个数据块存储单个颜色的数据通道,以与DXT5中的Alpha数据相同的方式进行编码,常用于存储高度图、光滑度贴图,效果与原始图像基本无差异;

  • 压缩比:2:1

b.2.2). ATI2(BC5, 4x4 8位)

每一个块中存储两个颜色通道的数据,同上以与DXT5中Alpha数据相同的方式进行编码,相当于存储了两个BC4块;

  • 压缩比:2:1

如果是在将法线存储在XY双通道中采用BC5格式压缩,由于每个通道都有自己的索引,因此法线贴图XY信息可以比在BC1中保留更多的保真度,缺点是需要使用两倍内存,也需要更多的带宽才能将纹理传递到着色器中;

b.3). BC6/7

BC6和BC7仅在D3D11级图形硬件中受支持,他们每个块占用16字节,BC7针对8位RGB或RGBA数据,而BC6针对RGB半精度浮点数据,因此BC6是唯一一个可以原生存储HDR的BC格式;

BC6是专门针对HDR(高动态范围)图像设计的压缩算法,压缩比为6:1;

BC7是专门针对LDR(低动态范围)图像设计的压缩算法,压缩比为3:1,该格式用于高质量的RGBA压缩,可以显著减少由于压缩法线带来的错误效果,但这也意味着解码所带来更多的消耗;

b.4). ETC

ETC(Ericsson Texture Compression)最初为移动设备开发,如今它是安卓的标准压缩方案,ETC1在OpenGL和OpenGL ES中都有支持。

将4x4 的像素块编码为2x4或4x2像素(64位)的两个块的方法,每个块指定一个基色,每个像素的颜色通过一个编码为相对于这些基色偏移的灰度值确定。

ETC

具体来说,ETC1每4x4像素块编码为64位的字节数据,每一个像素块又分为两个2x4子块(由一个“flip”位控制水平或竖直划分),每个子块包含一个3位的修饰表索引(modifier table index)和一个基本颜色值,这两个颜色值要么是2*R4G4B4要么是R5G5B5+R3G3B3(由一个“ diff”位控制是哪一种)。

ETC1

  • 24位颜色块(RGB444x2 或 RGB333+RGB555)
  • 2x4位亮度索引
    • 2x3位用于修饰表索引(索引table中列数)
    • 2x1位用于flip或diff(如左边块为flip,右边块为diff)
  • 每个像素中2位像素索引,索引对应列中行数
  • ETC2是ETC1的扩展,支持了Alpha通道的压缩,硬件要求OpenGL ES 3.0和OpenGL 4.3以上;

b.5). ASTC

ASTC是由ARM和AMD联合开发的纹理压缩格式,ASTC在各项指标上都挺不错,优点是可根据不同图片选择不同压缩率的算法,图片不需要为2的幂次,同时支持LDR和HDR,缺点是兼容性不够完善且解码时间较长

ASTC也是基于块的压缩算法,与BC7类似,其数据块大小固定为128位,不同的是块中的像素数量可变,从4×4到12×12像素都有;

每一个数据块中存储了两个插值端点,但不一定存储的是颜色信息,也可能是Layer信息,这样可以用来对Normal或Alpha进行更好的压缩;

对于块中每一个纹素,存储其对应插值端点的权重,存储的权重数量可以少于纹素数量,可通过插值得到每一个纹素的权重值,然后再进行颜色的计算;

  • 11位:权重、高度信息,特殊块标识;

  • 2位:Part数量;

  • 4位:16种插值端点模式(如LDR/HDR,RGB/RGBA);

  • 111位:插值端点信息,纹素权重值,配置信息;

b.6). PVRTC

PVRTC由Imagination公司专为PowerVR显卡设计,仅支持Iphone、Ipad和部分安卓机;

不同于DXTC和ETC这类基于块的算法,PVRTC将图像分为了低频信号和高频信号,低频信号由两张低分辨率图像AB组成,高频信号则是低精度的调制图像,记录了每个像素混合的权重,解码时AB图像经过双线性插值放大,然后根据调制图像的权重进行混合;

PVRTC 4-bpp(bit per pixel)把一个4×4的像素单元压成一个64位数据块,每一个块中存储一个32位的调制数据,一个1位的调制标志,15位的颜色$color_a$,1位颜色A不透明标志,14位颜色$color_b$,1位颜色B不透明标志;

  • 15+14位:储存RGB时,$color_a$ 是 RGB555,$color_b$ 是 RGB554

    ​ 储存RGBA时,$color_a$ 是 RGBA4443,$color_b$ 是 RGBA4433

  • 16x2位:每个像素2位调制数据

  • 1位:调制模式,0/1位不同模式得到两颜色的Alpha值(混合值)
  • 1+1位不透明标志:决定使用RGB/RGBA储存模式($a1 || a2$, 哪个高选哪个)

而PVRTC 2-bpp则是把一个8×4的像素单元压成了64位数据块;

c). 对比

  • 画质比较(参考)

    RGBA > ASTC 4×4 > ASTC 6×6 > ETC2 ≈ ETC1

  • 压缩比

    Rate

d). 格式使用建议

PC:

  1. 低质量使用DXT1格式不支持A通道,使用DXT5格式支持A通道;
  2. 高质量使用BC7格式,支持A通道;

安卓:

  1. 低质量使用ETC1格式,但不支持A通道;
  2. 低质量使用ETC2格式,支持A通道,需要在OpenGL ES 3.0/OpenGL 4.3以上版本;
  3. 高质量使用ASTC格式,需要在Android 5.0/OpenGL ES 3.1以上版本;

IOS:

  1. 高质量使用ASTC格式,需要iPhone6以上版本;
  2. 低质量使用PVRTC2格式,支持iPhone6以下版本;

【补充链接】

https://docs.unity3d.com/cn/current/Manual/class-TextureImporterOverride.html