KTX 工具实战:从安装到批量转换
如果你在做图形渲染资源优化,ktx 是一个非常值得掌握的命令行工具。它可以把 PNG/JPG 等纹理转成 GPU 友好的 KTX/KTX2 格式,并支持压缩、mipmap、色彩空间标记等关键能力。
1. KTX 是什么?常见类型有哪些?
1.1 容器格式层面
| 类型 | 后缀 | 说明 |
|---|---|---|
| KTX1 | .ktx |
早期格式,兼容性历史包袱较多 |
| KTX2 | .ktx2 |
新一代格式,推荐优先使用 |
通常新项目建议直接用 KTX2。
1.2 压缩编码层面(KTX2 常见)
| 编码 | 特点 | 适合场景 |
|---|---|---|
| UASTC | 画质高、细节好,体积通常更大 | 法线贴图、近景高质量材质 |
| ETC1S | 压缩率高、体积小,质量相对保守 | 包体敏感、移动端大规模分发 |
简单理解:要质量选 UASTC,要体积选 ETC1S。
2. 如何安装 KTX 工具
ktx 来自 Khronos 的 KTX-Software。
Ubuntu / Debian
1
2
sudo apt update
sudo apt install -y ktx-tools
macOS(Homebrew)
1
brew install ktx
Windows
从 KTX-Software 的 GitHub Releases 下载预编译包,解压后把可执行文件目录加入 PATH。
验证安装
1
ktx --help | head
看到帮助输出即安装成功。
3. ktx 最常用命令
不同版本子命令可能略有差异,但核心思路一致:创建(create)→ 检查(info)→ 转码/优化(视版本支持)。
3.1 单张图片转 KTX2(UASTC)
1
ktx create --encode uastc --format R8G8B8A8_SRGB --generate-mipmap input.png output.ktx2
参数要点:
--encode uastc:使用 UASTC 编码--format ...:显式指定像素格式(非常重要)--generate-mipmap:自动生成 mip 链
3.2 单张图片转 KTX2(ETC1S)
1
ktx create --encode etc1s --format R8G8B8A8_SRGB --generate-mipmap input.png output.ktx2
3.3 查看文件信息
1
ktx info output.ktx2
可用于确认编码类型、mipmap 层级、颜色空间标记等。
4. 批量转换:纯命令行方案
Linux / macOS(Bash)
4.1 批量转 UASTC(颜色纹理,sRGB)
1
2
3
4
5
mkdir -p out_ktx2
for f in textures/*.png; do
base="$(basename "$f" .png)"
ktx create --encode uastc --format R8G8B8A8_SRGB --generate-mipmap "$f" "out_ktx2/${base}.ktx2"
done
4.2 批量转 ETC1S(颜色纹理,sRGB)
1
2
3
4
5
mkdir -p out_ktx2
for f in textures/*.png; do
base="$(basename "$f" .png)"
ktx create --encode etc1s --format R8G8B8A8_SRGB --generate-mipmap "$f" "out_ktx2/${base}.ktx2"
done
5. 颜色空间与贴图类型:最容易出错的地方
5.1 颜色纹理(BaseColor / Emissive)
一般用 sRGB 格式,例如:
R8G8B8_SRGBR8G8B8A8_SRGB
5.2 数据纹理(Normal / Roughness / Metallic / AO)
一般用线性 UNORM:
R8G8B8_UNORMR8G8B8A8_UNORM
不要把法线、粗糙度等数据图当 sRGB。
否则常见症状是:高光异常、法线方向怪异、材质能量失真。
6. 常见问题与对应处理方式
问题 1:ktx: command not found
原因:未安装或 PATH 未配置。
处理:重新安装,并确认 ktx --help 能输出。
问题 2:转换成功但画面发灰/过亮
原因:色彩空间选错(把颜色图当线性,或反过来)。
处理:颜色图用 *_SRGB,数据图用 *_UNORM。
问题 3:体积太大
原因:使用了 UASTC 或纹理分辨率过高。
处理:改用 ETC1S;必要时先降采样再编码。
问题 4:细节损失明显
原因:ETC1S 对高频细节保真较弱。
处理:改用 UASTC,或对关键纹理单独走高质量策略。
问题 5:运行时加载失败
原因:引擎/驱动对目标格式支持不一致,或元数据不匹配。
处理:先 ktx info 检查文件,再验证运行时支持矩阵(API/平台/GPU)。
7. 一套可落地的选择建议
- 默认输出 KTX2。
- 颜色图和数据图分开处理,明确 sRGB/UNORM。
- 大多数贴图用 ETC1S 控体积,关键质量贴图用 UASTC。
- 始终生成 mipmap,减少闪烁与采样噪点。
- 每批次抽样用
ktx info+ 引擎实机检查。
按这套流程,你就能把 KTX 工具稳定纳入资源管线:体积、质量、加载效率三者可控。
参考脚本
convert_to_ktx2.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#!/bin/bash
# Convert PNG textures to KTX2 (UASTC supercompression) for GPU-native loading.
# Output goes to textures_ktx/ alongside the original textures/ folder.
#
# Usage: ./scripts/convert_to_ktx2.sh [texture_dir]
# texture_dir defaults to res/model/halo/textures
set -euo pipefail
SRC_DIR="${1:-res/model/halo/textures}"
DST_DIR="$(dirname "$SRC_DIR")/textures_ktx"
if ! command -v ktx &>/dev/null; then
echo "ERROR: 'ktx' tool not found. Install KTX-Software." >&2
exit 1
fi
if ! command -v identify &>/dev/null; then
echo "ERROR: 'identify' (ImageMagick) not found." >&2
exit 1
fi
mkdir -p "$DST_DIR"
# Textures that represent color data and must be tagged sRGB:
is_srgb() {
local name="$1"
[[ "$name" == *BaseColor* ]] || [[ "$name" == *Colour* ]] || \
[[ "$name" == *Specular* ]] || [[ "$name" == *Emissive* ]]
}
shopt -s nullglob
ok=0; fail=0
for src in "$SRC_DIR"/*.png "$SRC_DIR"/*.PNG; do
name=$(basename "$src" .png)
name=$(basename "$name" .PNG)
out="$DST_DIR/${name}.ktx2"
# Detect alpha channel via ImageMagick identify
channels=$(identify -format "%[channels]" "$src" 2>/dev/null | head -1)
has_alpha=false
[[ "$channels" == *"a"* ]] && has_alpha=true
# Select VkFormat based on color space and alpha
if is_srgb "$name"; then
$has_alpha && fmt="R8G8B8A8_SRGB" || fmt="R8G8B8_SRGB"
tf_flag=""
else
$has_alpha && fmt="R8G8B8A8_UNORM" || fmt="R8G8B8_UNORM"
tf_flag="--assign-tf linear"
fi
echo "[ktx2] $name fmt=$fmt"
if ktx create --encode uastc --format "$fmt" $tf_flag \
--generate-mipmap "$src" "$out" 2>/dev/null; then
(( ok++ )) || true
else
echo " FAILED: $src" >&2
(( fail++ )) || true
fi
done
echo ""
echo "Done. Converted: $ok Failed: $fail"
echo "Output: $DST_DIR/"