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、小程式,每種場景到底該用哪種組合。

贊助支持