Kris

KTX2 实战:纹理压缩的正确打开方式

3D 压缩纹理压缩KTX2Basis UniversalglTF

上一篇把 GPU 纹理格式、Basis Universal、KTX2 的关系讲清楚了。道理懂了,这篇全是动手:ETC1S 和 UASTC 怎么选、用什么工具、命令怎么敲、引擎里怎么加载。

可以照着抄,边看边做。

先解决最重要的一个选择:ETC1S 还是 UASTC

Basis 提供两种中间编码,选错了不是「不够好」的问题,而是法线贴图直接糊掉。先把这张表记住:

ETC1SUASTC
压缩率极高(类似 JPG)中等(类似高质量 PNG)
画质颜色类贴图够用接近原始质量
显存(转码后)通常 4bpp(约 1/8 原始)通常 8bpp(约 1/4 原始)
编码速度慢(可调级别)较快
适用albedo/漫反射、emissivenormal、metalness-roughness、数据贴图
不适用normal、需要精确数值的图颜色贴图(杀鸡用牛刀,体积偏大)

为什么法线贴图不能用 ETC1S?因为法线贴图存的是方向向量,每个像素的 RGB 三个通道互相约束(向量长度 ≈ 1)。ETC1S 是为「颜色看起来对」设计的块压缩,它对单通道精度不敏感,压完之后向量方向会偏,光照立刻显得不对——尤其是高光位置和高频细节。UASTC 对数值保留得更好,能扛住这种精度要求。

实用规则

  • 颜色贴图(albedo、emissive)→ ETC1S
  • 数据贴图(normal、roughness、metallic、AO、thickness)→ UASTC
  • 拿不准、又想省体积 → 先试 ETC1S,特写下糊了再换 UASTC

同一张图,四种格式比一比

用一张 2048×2048 的 albedo 贴图做基准(数据为社区典型值,仅供参考):

格式磁盘大小显存占用(含 mipmap)上传到 GPU跨平台
PNG~5MB~22MB
WebP~1MB~22MB
KTX2 (ETC1S)~0.5-0.8MB~2.8MB
KTX2 (UASTC)~3-4MB~5.6MB

注意 WebP 的显存占用和 PNG 一样——它只是磁盘小,进了显存照样解压成原始像素。KTX2 的 ETC1S 把磁盘和显存同时打到很低,这就是它值钱的地方。

工具链:三条路都通

压缩 KTX2 的工具不止一个,按「顺手程度」排:

1. toktx(官方、最强大)

Khronos 官方工具,参数最全,适合单独处理纹理。

# 把 PNG 转成 ETC1S 编码的 KTX2
toktx --bcmp --uastc 0 albedo.ktx2 albedo.png

# 把 PNG 转成 UASTC 编码的 KTX2
toktx --uastc 1 normal.ktx2 normal.png

常用参数:

# ETC1S + 质量档位(1-255,默认 128,越高画质越好体积越大)
toktx --bcmp --uastc 0 --qlevel 200 albedo.ktx2 albedo.png

# UASTC + 超级压缩(Zstandard,进一步缩小磁盘体积)
toktx --uastc 1 --zcmp 19 normal.ktx2 normal.png

# 自动生成 mipmap(强烈建议加)
toktx --bcmp --genmipmap albedo.ktx2 albedo.png

# 指定 sRGB 色彩空间(颜色贴图必须)
toktx --bcmp --srgb albedo.ktx2 albedo.png

--bcmp 是 ETC1S 模式的开关(Basis Universal 的基础模式),--uastc 1 是 UASTC 模式。两者互斥。

2. gltf-transform(最省事,强烈推荐)

如果你手上是整个 glTF/GLB 模型,用 gltf-transform 一条命令把里面所有纹理换成 KTX2,按贴图用途自动选 ETC1S/UASTC。

# 安装
npm install -g @gltf-transform/cli

# 一键压缩整个模型
gltf-transform optimize model.glb model-optimized.glb \
  --texture-compress basisu

它内部会判断贴图用途:颜色类用 ETC1S,数据类用 UASTC,并自动写好 KHR_texture_basisu 扩展。这是 90% 场景的最佳选择,不用一个个手动敲 toktx。

3. 在线工具(最快上手)

不想装环境时,直接用浏览器工具:gltf.report(在线版 gltf-transform)、KTX2 Converter 等。上传,下载,完事。适合早期试验或一次性任务。

完整 pipeline:从源文件到上线

整理一下标准流程(流程图):

源文件(PNG/JPG/PSD/TGA)
        │
        ├── [整模型] gltf-transform optimize model.glb → 自动识别贴图类型
        │            └─ 颜色贴图 → ETC1S
        │            └─ 数据贴图 → UASTC
        │            └─ 写入 KHR_texture_basisu 扩展
        │
        └── [单张贴图] toktx → 手动指定 ETC1S/UASTC + 色彩空间 + mipmap
        │
        ▼
压缩后的 KTX2 / GLB
        │
        ▼
引擎加载(Three.js / Babylon.js)── 运行时转码 → GPU 原生格式

Three.js 里加载 KTX2

Three.js 从 r129 起原生支持 KTX2:把 KTX2Loader(指定 basis transcoder wasm 路径、探测 GPU 能力)挂到 GLTFLoader,之后加载含 KTX2 纹理的 glTF 会自动转码。

const ktx2Loader = new KTX2Loader().setTranscoderPath("/basis/").detectSupport(renderer);
gltfLoader.setKTX2Loader(ktx2Loader); // 模型若同时用 Draco/MeshOpt,记得一并挂 DRACOLoader / MeshoptDecoder

detectSupport(renderer) 必须调——它决定运行时转码成哪种原生格式。另外颜色贴图要设 texture.colorSpace = THREE.SRGBColorSpace,漏设就是经典的「整张图发灰」坑(normal/roughness 等数据贴图保持线性)。

Babylon.js 里加载 KTX2

Babylon 更省心——GLTFFileLoader 默认开启 KHR_texture_basisu,并自动从 CDN 拉取 basis transcoder,加载含 KTX2 的 glTF 开箱即用。离线/内网环境需手动配置 BASISFileLoader.TranscoderModule

压缩参数调优:质量与体积的平衡

ETC1S 的核心参数是 --qlevel(1-255)。它怎么影响结果:

qlevel体积画质编码耗时适用
128(默认)够用多数情况
200-255偏大接近无损长(数倍)高质量要求
60-100很小有可见块状远景/小贴图

UASTC 体积相对固定,主要靠 --zcmp(Zstandard 超级压缩)调磁盘大小,不影响显存(解压后还是 8bpp)。

调优顺序建议:

  1. 先用默认参数压一遍,看体积和画质
  2. 不满意 → 调 --qlevel(ETC1S)或加 --zcmp(UASTC)
  3. 法线贴图糊了 → 确认用的是 UASTC,不是 ETC1S
  4. 颜色偏暗 → 检查色彩空间设置(sRGB 标志、引擎里的 colorSpace)

常见问题排查

转码失败 / 加载报错

  • 检查 transcoder wasm 路径是否正确(Three.js 要 setTranscoderPath
  • 检查引擎版本是否支持当前 KTX2 版本(旧版 basis 编码不被新版 transcoder 支持)
  • 控制台通常会有具体错误,按关键词搜

颜色偏暗 / 偏亮

  • 颜色贴图(albedo)没设 sRGB,或设反了
  • toktx 时漏了 --srgb(颜色贴图要加)
  • 数据贴图(normal)误加了 sRGB

mipmap 缺失,远处闪烁

  • 压缩时没加 --genmipmap
  • 引擎里 texture.generateMipmaps 没开(Three.js 里 KTX2 默认随文件,但仍需材质 minFilter 用 mipmap 模式)

特写下法线方向不对

  • 法线贴图用了 ETC1S,换 UASTC
  • 确认法线贴图是 OpenGL 风格(绿色通道朝上),DirectX 风格在某些引擎里要翻转 G 通道

文件反而变大了

  • 小尺寸贴图(< 128×128)用 KTX2 不划算,块压缩有固定开销,会占满整个块
  • 纯色贴图别压 KTX2,直接用材质色值更省

下一步

纹理压缩这块到这就基本通关了。但「会用工具」不等于「会用对工具」——下一篇把前 4 篇的所有知识汇总成一个选型框架:桌面、移动、VR、小程序,每种场景到底该用哪种组合。

赞助支持