法线贴图的压缩格式比较
这几天一直在忙着在 bgfx 上增加 ASTC 格式的法线贴图支持 。
法线贴图上的法线向量虽然有三个分量,但是它们是归一化的。而且,切线空间上的法线贴图的第三个向量 Z 总是正值,所以我们只需要用两个分量就可以保存下法线信息,在运行时再计算出第三个向量。
不过这种方法有一个问题,贴图采样的时候,由于是线性插值,所以计算出来的第三个向量可以和实际差的较远。通常的解决方法是保存球形投影的 X Y 分量,减少 Z 的偏差。具体可以看看 Nvidia 的这篇 Real-Time Normal Map DXT Compression 。
显卡硬件一开始并不支持的双通道压缩贴图,所以最早使用这个算法的 Id 是用 dxt5 模拟的,使用 Dxt5 的 RGB 中的 G 保存一个通道,再用 A 保存另一个通道。后来的 EAC_RG11
则直接支持了双通道压缩贴图。
ASTC 虽然没有特别支持双通道贴图,但是它的 encoder 可以把信息权重放在两个通道上,这样就可以在同样的 bpp 下,让双通道信息的误差更小。
bgfx 自带的贴图压缩工具没有支持这样的压缩参数,我最近的工作就是完善它。
bgfx 的 astc 支持是做足球经理项目的同学提的,我在几个月前提了个 issue 希望他能完善一下,可能是他工作很忙,一直没有回音。最近我们自己的项目向手机 port ,必须用到压缩法线贴图了(不然内存不够),只能自己动手。好在这样也就激活了这件事,现在那位同学已经自己开始干了。
btw, 这次发现我向 bimg 提的 pr ,居然可以跨仓库合并到 astc_encoder
项目上,而保留 patch 的作者和时间信息等。我一直不知道 git 还有跨仓库合并 patch 的功能 :)
这事我起了个头,不用自己做了,很开心。多出来的时间,我饶有兴趣的比较几种压缩格式的质量。
首先,图形有损压缩的质量衡量标准,业界一般采用 PSNR 峰值信噪比 。这个值越高,表示压缩质量越好。不过也不完全唯 PSNR 论。ASTC 和 ETC 的官方压缩器都提供了一个叫 percep 的选项,它的 psnr 差不多(略低)但号称对人的视觉上感觉更好。etcpack 更是把它作为默认选项。
我使用了 Nvidia 的贴图压缩工具 生成 DXT 格式贴图,ARM 的 astcencoder 生成 astc 格式贴图,Ericsson 的 etcpack 生成 etc 格式贴图。
astc encoder 有一个文档 专门说明法线贴图的压缩方案。
我今天使用了 Unity 官方公开的一个场景中使用的 2048x2048 的切线空间法线贴图。原始图片可以在这里找到。
下表是我的比较结果:
encode tools | format | channels | bpp | command options | PSNR (dB) higher is better |
nvcompress | dxt1nm | RGB | 4 | -nomips -normal -bc1n | 27.484683 |
astcenc | astc 6x5 | RG | 4.27 | -t 4.0 -normal_psnr -thorough | 29.670458 |
astcenc | astc 4x4 | RGB | 8 | -t 8.0 -thorough | 33.238881 |
astcenc | astc 5x4 | RG | 6.4 | -t 6.0 -normal_psnr -thorough | 33.839983 |
astcenc | astc 5x4 | RG | 6.4 | -t 6.0 -normal_psnr -thorough | 33.839983 |
nvcompress | dxt5nm | RG | 8 | -nomips -normal -bc3n | 34.518504 |
astcenc | astc 4x4 | RG | 8 | -t 8.0 -normal_percep -fast | 35.779205 |
astcenc | astc 4x4 | RG | 8 | -t 8.0 -normal_psnr -fast | 36.121064 |
astcenc | astc 4x4 | RG | 8 | -t 8.0 -normal_percep -thorough | 37.030079 |
astcenc | astc 4x4 | RG | 8 | -t 8.0 -normal_psnr -thorough | 37.403131 |
etcpack | EAC_RG11 | RG | 8 | -f RG | 40.834371 |
PSNR 全部是用 astcenc 计算得到,因为 nvidia 的工具生成并还原的贴图只有两个通道,其它工具会还原成三通道。为了公平起见,我用 imagemagik 把结果中的 blue 通道全部清空再做计算。
我们可以发现,etcpack 生成的 EAC_RG11
质量最好,不过 etcpack 的算法实现实在是太糟糕了,慢的令人发指。同样一张 2048 的图,nvidia 压缩 dxt 只需要一秒,etcpack 需要跑几分钟。前段时间我自己实现过一个版本 ,可以把 O(n*n) 的时间复杂度降低到 O(n) 。
dxt 的质量最差,当然这个格式也最古老。
astc 最具弹性,选择 6bpp 就能到达到 dxt 8bpp 的质量。针对双通道的优化质量提升也很明显。而且在追求更小体积时,还可以选择更低质量(这点 EAC 做不到)。
Comments
Posted by: 灵卦 | (5) September 11, 2019 01:56 PM
Posted by: 甄 | (4) August 2, 2019 03:28 PM
Posted by: 杨邦旻 | (3) July 24, 2019 11:34 AM
Posted by: 江湖 | (2) July 21, 2019 01:25 PM
Posted by: tpkeeper | (1) July 19, 2019 01:18 PM