KTX2 in der Praxis: Der richtige Umgang mit Texturkomprimierung
Im vorherigen Artikel haben wir die Beziehung zwischen GPU-Texturformaten, Basis Universal und KTX2 geklärt. Die Theorie ist verstanden – jetzt geht es ans Eingemachte: Wie wählt man zwischen ETC1S und UASTC, welche Tools verwendet man, wie lauten die Befehle, und wie lädt man die Texturen in der Engine?
Sie können direkt mitkopieren und Schritt für Schritt mitmachen.
Zuerst die wichtigste Entscheidung: ETC1S oder UASTC
Basis bietet zwei Zwischenkodierungen. Die falsche Wahl führt nicht nur zu „nicht ausreichender Qualität", sondern zu verschwommenen Normal Maps. Merken Sie sich diese Tabelle:
| ETC1S | UASTC | |
|---|---|---|
| Kompressionsrate | Sehr hoch (ähnlich JPEG) | Mittel (ähnlich hochwertigem PNG) |
| Bildqualität | Ausreichend für Farb-Texturen | Nahe an der Originalqualität |
| VRAM (nach Transkodierung) | Typischerweise 4bpp (ca. 1/8 der Originalgröße) | Typischerweise 8bpp (ca. 1/4 der Originalgröße) |
| Kodierungsgeschwindigkeit | Langsam (stufenweise einstellbar) | Schnell |
| Geeignet für | Albedo/Diffuse, Emissive | Normal, Metalness-Roughness, Daten-Texturen |
| Nicht geeignet für | Normal, texturierte Daten mit präzisen Werten | Farb-Texturen (mit Kanonen auf Spatzen schießen, größer) |
Warum können Normal Maps nicht mit ETC1S verwendet werden? Weil Normal Maps Richtungsvektoren speichern, bei denen die drei RGB-Kanäle jedes Pixels miteinander verbunden sind (Vektorlänge ≈ 1). ETC1S ist eine Blockkomprimierung, die dafür ausgelegt ist, dass Farben „richtig aussehen". Sie ist nicht empfindlich für die Genauigkeit einzelner Kanäle. Nach der Komprimierung werden die Vektorrichtungen verzerrt, die Beleuchtung wirkt sofort falsch – insbesondere bei Glanzlichtern und hochfrequenten Details. UASTC bewahrt die numerischen Werte besser und erfüllt diese Genauigkeitsanforderungen.
Praktische Regel:
- Farb-Texturen (Albedo, Emissive) → ETC1S
- Daten-Texturen (Normal, Roughness, Metallic, AO, Thickness) → UASTC
- Im Zweifel und bei Platzersparnis → zuerst ETC1S versuchen, bei Nahaufnahmen unscharf dann auf UASTC wechseln.
Vergleich von vier Formaten am selben Bild
Vergleichen wir eine 2048×2048 Albedo-Textur (Daten aus der Community, nur als Referenz):
| Format | Dateigröße | VRAM (mit Mipmaps) | Hochladen auf GPU | Plattformunabhängig |
|---|---|---|---|---|
| PNG | ~5 MB | ~22 MB | Langsam | ✅ |
| WebP | ~1 MB | ~22 MB | Langsam | ✅ |
| KTX2 (ETC1S) | ~0,5–0,8 MB | ~2,8 MB | Schnell | ✅ |
| KTX2 (UASTC) | ~3–4 MB | ~5,6 MB | Schnell | ✅ |
Beachten Sie: WebP belegt genauso viel VRAM wie PNG – es ist nur auf der Festplatte kleiner, wird aber im VRAM dennoch zu den ursprünglichen Pixeln dekomprimiert. KTX2 mit ETC1S reduziert sowohl Festplatten- als auch VRAM-Nutzung drastisch – das ist sein Wert.
Toolchain: Drei Wege führen zum Ziel
Es gibt mehrere Tools, um KTX2 zu komprimieren. Hier sind sie nach „Bequemlichkeit" sortiert:
1. toktx (offiziell, am leistungsfähigsten)
Das offizielle Tool von Khronos, mit den meisten Parametern, geeignet für die separate Verarbeitung von Texturen.
# PNG in ETC1S-kodiertes KTX2 konvertieren
toktx --bcmp --uastc 0 albedo.ktx2 albedo.png
# PNG in UASTC-kodiertes KTX2 konvertieren
toktx --uastc 1 normal.ktx2 normal.png
Häufig verwendete Parameter:
# ETC1S + Qualitätsstufe (1–255, Standard 128, höher = bessere Qualität, größere Datei)
toktx --bcmp --uastc 0 --qlevel 200 albedo.ktx2 albedo.png
# UASTC + Superkomprimierung (Zstandard, reduziert weitere Dateigröße)
toktx --uastc 1 --zcmp 19 normal.ktx2 normal.png
# Automatische Mipmap-Erzeugung (dringend empfohlen)
toktx --bcmp --genmipmap albedo.ktx2 albedo.png
# sRGB-Farbraum angeben (für Farb-Texturen zwingend erforderlich)
toktx --bcmp --srgb albedo.ktx2 albedo.png
--bcmpist der Schalter für den ETC1S-Modus (Basis Universal Basis-Modus),--uastc 1für den UASTC-Modus. Beide schließen sich gegenseitig aus.
2. gltf-transform (am bequemsten, wärmstens empfohlen)
Wenn Sie ein komplettes glTF/GLB-Modell haben, verwenden Sie gltf-transform mit einem Befehl, um alle Texturen im Modell in KTX2 zu konvertieren und automatisch je nach Verwendungszweck ETC1S oder UASTC auszuwählen.
# Installation
npm install -g @gltf-transform/cli
# Einfach das gesamte Modell komprimieren
gltf-transform optimize model.glb model-optimized.glb \
--texture-compress basisu
Es erkennt intern den Verwendungszweck der Texturen: Farb-Texturen → ETC1S, Daten-Texturen → UASTC, und schreibt automatisch die KHR_texture_basisu-Erweiterung. Dies ist die beste Wahl für 90% der Fälle – Sie müssen nicht manuell toktx für jede Textur ausführen.
3. Online-Tools (schnellster Einstieg)
Wenn Sie keine Umgebung einrichten möchten, nutzen Sie Browser-Tools: gltf.report (Online-Version von gltf-transform), KTX2 Converter usw. Hochladen, herunterladen, fertig. Ideal für frühe Experimente oder einmalige Aufgaben.
Vollständige Pipeline: Von der Quelldatei zur Auslieferung
Hier ist der Standardablauf (Ablaufdiagramm):
Quelldatei (PNG/JPG/PSD/TGA)
│
├── [Ganzes Modell] gltf-transform optimize model.glb → automatische Erkennung des Texturtyps
│ └─ Farb-Textur → ETC1S
│ └─ Daten-Textur → UASTC
│ └─ Schreibt KHR_texture_basisu-Erweiterung
│
└── [Einzelne Textur] toktx → manuelle Angabe von ETC1S/UASTC + Farbraum + Mipmap
│
▼
Komprimiertes KTX2 / GLB
│
▼
Engine-Laden (Three.js / Babylon.js) ── Laufzeit-Transkodierung → GPU-natives Format
Laden von KTX2 in Three.js
Three.js unterstützt KTX2 nativ ab r129: Hängen Sie KTX2Loader (mit Pfad zum Basis-Transcoder-Wasm, GPU-Erkennung) an GLTFLoader. Anschließend werden glTF-Modelle mit KTX2-Texturen automatisch transkodiert.
const ktx2Loader = new KTX2Loader().setTranscoderPath("/basis/").detectSupport(renderer);
gltfLoader.setKTX2Loader(ktx2Loader); // Wenn das Modell auch Draco/MeshOpt verwendet, denken Sie daran, auch DRACOLoader / MeshoptDecoder zu laden
detectSupport(renderer) muss aufgerufen werden – es bestimmt, in welches native Format zur Laufzeit transkodiert wird. Außerdem müssen Farb-Texturen mit texture.colorSpace = THREE.SRGBColorSpace versehen werden – fehlt dies, erscheint das klassische „das ganze Bild ist grau"-Problem (Normal-/Roughness-Texturen bleiben linear).
Laden von KTX2 in Babylon.js
Babylon ist noch einfacher: GLTFFileLoader aktiviert standardmäßig KHR_texture_basisu und lädt den Basis-Transcoder automatisch von einem CDN. Das Laden von glTF mit KTX2-Texturen funktioniert sofort. In Offline-/Intranet-Umgebungen müssen Sie BASISFileLoader.TranscoderModule manuell konfigurieren.
Optimierung der Komprimierungsparameter: Balance zwischen Qualität und Größe
Der Kernparameter von ETC1S ist --qlevel (1–255). Wie wirkt er sich aus?
| qlevel | Größe | Bildqualität | Kodierungszeit | Anwendung |
|---|---|---|---|---|
| 128 (Standard) | Klein | Ausreichend | Mittel | Meiste Fälle |
| 200–255 | Eher groß | Nahezu verlustfrei | Lang (mehrere Male) | Hohe Qualitätsanforderungen |
| 60–100 | Sehr klein | Sichtbare Blockartefakte | Schnell | Weit entfernte / kleine Texturen |
Die Größe von UASTC ist relativ fest, hauptsächlich über --zcmp (Zstandard-Superkomprimierung) wird die Dateigröße beeinflusst, nicht der VRAM (nach Dekomprimierung immer noch 8bpp).
Empfohlene Optimierungsreihenfolge:
- Zuerst mit Standardparametern komprimieren, Größe und Qualität prüfen
- Nicht zufrieden →
--qlevel(ETC1S) anpassen oder--zcmp(UASTC) hinzufügen - Normal Map unscharf → sicherstellen, dass UASTC verwendet wird, nicht ETC1S
- Farben zu dunkel → Farbraumeinstellungen überprüfen (sRGB-Flag, colorSpace in der Engine)
Häufige Probleme und Lösungen
Transkodierungsfehler / Lade-Fehler
- Überprüfen Sie den Pfad zum Transcoder-Wasm (Three.js benötigt
setTranscoderPath) - Überprüfen Sie, ob die Engine-Version die aktuelle KTX2-Version unterstützt (alte Basis-Kodierung wird von neuen Transcoder-Versionen nicht unterstützt)
- Die Konsole zeigt normalerweise konkrete Fehler an, suchen Sie nach dem Schlüsselwort
Farben zu dunkel / zu hell
- Farb-Textur (Albedo) hat kein sRGB oder ist falsch eingestellt
- Bei toktx fehlt
--srgb(für Farb-Texturen erforderlich) - Daten-Textur (Normal) hat fälschlicherweise sRGB erhalten
Fehlende Mipmaps, Flimmern in der Ferne
- Bei der Komprimierung wurde
--genmipmapnicht verwendet - In der Engine ist
texture.generateMipmapsnicht aktiviert (Three.js: KTX2 hat standardmäßig Mipmaps, aber derminFilterder Material muss den Mipmap-Modus verwenden)
Falsche Normalenrichtung bei Nahaufnahmen
- Normal Map verwendet ETC1S → wechseln zu UASTC
- Stellen Sie sicher, dass die Normal Map OpenGL-Stil ist (grüner Kanal zeigt nach oben), DirectX-Stil erfordert manchmal das Invertieren des G-Kanals in der Engine
Datei ist größer geworden
- Kleine Texturen (< 128×128) lohnen sich nicht für KTX2, da Blockkomprimierung einen festen Overhead hat und den gesamten Block füllt
- Reine Farb-Texturen nicht in KTX2 komprimieren, sondern direkt den Farbwert im Material verwenden
Nächster Schritt
Damit sind die Grundlagen der Texturkomprimierung abgeschlossen. Aber „das Werkzeug benutzen können" ist nicht gleich „das richtige Werkzeug benutzen" – im nächsten Artikel fassen wir das Wissen der letzten vier Artikel in einem Entscheidungsrahmen zusammen: Desktop, Mobil, VR, Mini-Programme – welche Kombination für jedes Szenario am besten geeignet ist.