« 用 skynet 实现 unity 的 cache server | 返回首页 | 程序员应该怎样提高自己 »

法线贴图的压缩格式比较

这几天一直在忙着在 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 toolsformatchannelsbppcommand optionsPSNR (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

No 4

第三

第二

第一

Post a comment

非这个主题相关的留言请到:留言本