JMonkeyEngine——压缩纹理制作
压缩纹理
这里说的纹理格式,不是JPG,PNG等纹理格式,而是一种方便GPU高效读取的格式.
通常的纹理压缩格式:
Bmp, Tga , PNG, jpg等文件压缩格式有一个关键问题,它们的压缩方式都是对图片整体压缩,比如使用霍夫曼编码,那么在解码过程中,像素和像素之间存在依赖关系, 无法实现单个像素级别的解析, GPU的并发执行优势无法体现,并且解码后是RGBA纹理格式,也无法减少内存占用率.
用于GPU的纹理压缩格式:
DXT,EXT, ETC,PVRTC,ASTC等格式的压缩方式,都是以 N x N(常见的如4x4, ASTC中有多种尺寸)的block为单元压缩的,解压时就几乎不需要其它周边信息(有些压缩格式会共享一些参考信息,比如ETC的亮度偏移表),每个block自成一体,可以被GPU随机,并行,快速解码采样,不需要CPU解压缩,极大的提高GPU采样效率,加载效率,同时减少显存占用和GPU现存带宽压力,提高帧率(显存带宽往往GPU帧率的瓶颈). 但副作用是,压缩格式将严重依赖GPU的型号(仅ASTC格式跨平台兼容性较好), 所以每个平台对于压缩格式的选择其实没有太大余地, 都相对固定. 所以在打包或者打bundle时,就会生成对应平台的纹理格式, 这也是不同平台资源不能共用的原因之一. 如果设置了目标平台不支持的纹理压缩格式,那将会在运行时解压缩为非压缩格式,如RGB24,就会增加一份内存占用.
更多请参考这篇文章:https://zhuanlan.zhihu.com/p/632248419。
对于压缩方式和对应的后缀,相关平台,如下:
-
DXT / S3TC(DirectX Texture Compression / S3 Texture Compression)
- 常见后缀:
.dds - 优点:广泛支持于 DirectX 和 OpenGL,压缩比高。
- 常见类型:DXT1、DXT3、DXT5
- 常见后缀:
-
**BC / BPTC(Block Compression / BPTC)
- 常见后缀:
.dds - 优点:支持更高质量的压缩和更广泛的纹理类型。
- 常见类型:BC1(与 DXT1 类似)、BC2(与 DXT3 类似)、BC3(与 DXT5 类似)、BC4、BC5、BC6H、BC7
- 常见后缀:
-
ETC(Ericsson Texture Compression)
- 常见后缀:
.ktx - 优点:广泛支持于移动设备和 OpenGL ES,适用于纹理资源受限的环境。
- 常见类型:ETC1、ETC2
- 常见后缀:
-
ASTC(Adaptive Scalable Texture Compression)
- 常见后缀:
.ktx - 优点:灵活的块大小选择,高效的压缩比,支持广泛的纹理类型。
- 常见类型:ASTC 4x4、ASTC 5x5、ASTC 6x6、ASTC 8x8、ASTC 10x10、ASTC 12x12
- 常见后缀:
-
PVRTC(PowerVR Texture Compression)
- 常见后缀:
.pvr - 优点:专为 PowerVR 图形处理器设计,广泛用于 iOS 设备。
- 常见类型:PVRTC1、PVRTC2
- 常见后缀:
-
Basis Universal(实际上不是一种gpu压缩纹理格式,而是一种中间数据,需要运行时实时调用目标gpu生成上诉对应的压缩纹理格式传递给gpu使用)
- 常见后缀:
.basis - 优点:跨平台支持,包括 Web、移动和桌面。能够在多种压缩格式之间高效转换。
- 支持模式:UASTC、ETC1S
- 常见后缀:
对于JME3桌面端,建议使用BC1、BC2、BC3这种压缩算法生成的.dds后缀的纹理数据,对于JME3移动端(Android和IOS),建议使用ASTC/ETC压缩算法生成的.ktx后缀的纹理数据。
需要注意的一点是:压缩纹理指压缩算法本身,不同gpu硬件支持的压缩解码算法通常有好几种而不限于一种,同一种后缀,比如.dds,可以使用ETC、BC1~7等压缩算法数据存储表示,所以后缀不是代表压缩纹理本身,当通常具有显著意义。
JME3SDK压缩纹理工具
SDK可以配置NVCompressTool,如下:


但这工具点击压缩后并没有生成对应文件,没搞懂怎么用,文档也没有介绍,只能去看工具源码,暂时放弃。
NVIDIA Texture Tools Exporter
建议安装NVIDIA Texture Tools Exporter,我使用的是2024.1.0版本,这个工具非常强大,而且免费使用,打开后如下:

直接拖纹理到右边或点击选择一个纹理,下面介绍几个非常重要的选项:

根据纹理类型,如果是法线贴图则选择NormalMap(切线空间或对象空间,蓝色法线纹理基本就是切线空间,如果包含红绿蓝颜色的法线纹理,则是对象空间);

Format表示你要使用那种gpu压缩纹理算法来生成纹理,不同算法可以生成的纹理文件后缀是不同的,对于JME3桌面端,如果我们希望纹理保存alpha通道,则选择BC1a,如果不希望纹理保存alpha通道,则选择BC1,对于移动端,我们选择UASTC/ETC1S,对于需要保存alpha通道的选择ETC1S RGBA这一项,UASTC不能丢弃alpha通道,如下我们选择BC1a:

Minimum MipmapSize表示最小的Mipmap数据为多少个像素数据,默认最小一级为1个pexel,Maximum Mipmap Count表示要生成多少级Mipmap,默认MAX为10级,注意,但这里显示MAX时,你直接填一个数字然后回车回变回MAX,你必须先点击右边的+号,让MAX变为1,然后才可以直接输入数字回车或继续通过+号添加需要的Count数量。

这里我填了5,表示需要生成5级Mipmap,右上角的滑动条,滑动可以查看对应级别的Mipmap纹理数据状态:


你可能会发现,最低一级Mipmap不止一个像素,这是因为生成5层时,最后Mipmap4按照指定Filter Type为Box来生成Mipmap,你可以尝试不同的Filter Type算法。
然后你可能需要将原始512x512的纹理改为128x128,则可以添加一个Effects:

选择Resize,然后调整缩放即可,你可以添加多个Effect,结果是叠加多个不同的图像处理结果。

Use DXT10 Header这一项不要选择,JME3默认不支持DXT10 Header。
最后选择保存,BC1/BC1a选择保存为dds格式:

如下是生成的.dds纹理和原始jpg纹理:


使用BC1a算法生成的dds包含5级Mipmap数据,不再需要运行时解析jpg数据并生成Mipmap这个过程开销,直接就可以上载到gpu内存中使用了。
对于android/ios平台,需要选择ETC1S或UASTC,生成后缀为KTX2的格式,你可能会觉得用BC1a算法并保存为KTX格式不就行了?不行,原因是不同的gpu对压缩纹理格式是有要求的,比如PC的gpu支持硬件解析BC1~7算法生成,但是android/ios的GPU系列(有好几种,Adreno,Mali,PowerVR,苹果自家的A系列)硬件只能解析ETC/ASTC/PVR等这几种数据,所以需要用对应的压缩算法生成对应的纹理,而不是后缀的问题。
AdrenoSDK
但是,虽说后缀不是主要问题,但JME貌似没有对KTX2做文件读取识别,默认是不支持的,这就很蛋疼,所以我们需要另一个工具来生成移动端KTX纹理。首先下载AdrenoSDK,地址为https://developer.qualcomm.com/download/adrenosdk/adreno-sdk.zip?referrer=node/6114。
然后进入按照目录运行QCompress.exe工具,如下:

然后打开对应的jpg/png纹理,选择ASTC/ETC压缩算法:

并选择启用Mipmap生成:

然后选择输出格式为KTX:

然后选择生成ktx纹理:

然后点击Process按钮或保存,生成对应压缩纹理:


如果你需要调整压缩算法、生成路径等,重新点击Options列下的Config按钮才可以进行修改:

JME中使用
创建一个测试材质和测试场景,对于dds纹理,可以直接通过材质编辑器赋值:

对于ktx,材质编辑器不识别,只能通过代码设置。
如下是测试结果:

拉远后自动Mipmap切换:

优化
如果说我们希望开发一个JME3游戏,然后材质中的纹理可以同时用于桌面和移动端,那么我们有两种做法:
- 通过逻辑,判断如果是移动端,则在loadModel()后遍历场景中所有Geometry的所有Material的所有Texture参数,并依次按照对应纹理名找到对应的ktx纹理加载覆盖掉
- 使用ETC/ASTC算法来压缩,桌面上也支持ETC等算法压缩硬件直读的纹理,所以可以用QCompress.exe工具生成基于ETC/ASTC算法的.dds后缀纹理
这里使用QCompress.exe并使用ETC2 RGBA8算法生成一张后缀为.dds的纹理:

然而,JME3 DDSLoader默认只能识别BC1~7压缩算法Header的dds纹理,这就需要我们修改DDSLoader插件的逻辑。

浙公网安备 33010602011771号