png纹理转换为ktx

Posted by shensunbo on April 11, 2026

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_SRGB
  • R8G8B8A8_SRGB

5.2 数据纹理(Normal / Roughness / Metallic / AO)

一般用线性 UNORM:

  • R8G8B8_UNORM
  • R8G8B8A8_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. 一套可落地的选择建议

  1. 默认输出 KTX2
  2. 颜色图和数据图分开处理,明确 sRGB/UNORM。
  3. 大多数贴图用 ETC1S 控体积,关键质量贴图用 UASTC。
  4. 始终生成 mipmap,减少闪烁与采样噪点。
  5. 每批次抽样用 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/"