Von Blender bis zum Live-Gang: ein End-to-End-Kompressions-Walkthrough
An diesem Punkt der Serie sind Werkzeuge, Prinzipien und Auswahl behandelt. In diesem letzten Artikel binden wir alles zu einer lauffähigen Pipeline zusammen: Ausgehend von einem realen Blender-Modell Schritt für Schritt komprimieren, bei jedem Schritt Dateigröße, VRAM und Ladezeit aufzeichnen und schließlich sehen, ob es sich von einem 50-MB-Schwergewicht zu einem 5-MB-Modell schrumpfen lässt, das auf dem Handy sofort öffnet.
Zielleser: wer die vorherigen fünf gelesen hat und wirklich loslegen will. Keine neuen Konzepte hier – nur kopierbare Abläufe, Befehle und Skripte.
Startpunkt: ein reales PBR-Modell
Als Sample ein sehr typisches E-Commerce-Demo-Modell: ein hochdetailliertes Produktmodell mit vollständigen PBR-Maps.
| Anfangsmetrik | Wert |
|---|---|
| Blender-Quelldatei | ~120 MB (inkl. nicht exportierter High-Poly) |
| Exportiertes GLB (float32 + PNG) | ~50 MB |
| Vertex-Anzahl | ~180k |
| Maps | 6 × 4096×4096 (albedo, normal, roughness, metallic, AO, emissive) |
| VRAM-Nutzung (6 vollständig dekomprimiert) | ~520 MB |
| Ziel | Datei ≤ 5 MB, VRAM kontrollierbar, auf Mobil sofort öffnen |
Eine 50-MB-Datei und 520 MB VRAM – dieses Modell crash auf Mobil garantiert. Gehen wir Schritt für Schritt vor.
Schritt 0: korrekt aus Blender exportieren
Die erste Hürde der Kompression ist tatsächlich der Export; viele bluten hier.
Wichtige Einstellungen beim glTF-Export aus Blender:
- Format:
glTF Binary (.glb)(einzelne Datei, einfach zu übertragen) - Geometrie:
Normals,Tangentsanhaken (PBR-Normal-Maps brauchen Tangenten) - UV: sicherstellen, dass exportiert wird (standardmäßig an)
- Texturen:
AutomaticoderJPEG(das Texturformat hier ist egal; wir komprimieren später neu – aber sie müssen exportiert sein) - Kompression: Blender-eigene Mesh-Kompression nicht anhaken; wir nutzen spezialisierte Werkzeuge
- Transform:
+Y Up(glTF-Standard) - Daten: nur Nötiges anhaken (Animation, Kameras, Lichter bei Nichtbedarf nicht exportieren, um Größe zu reduzieren)
Nach dem Export model.glb: 50 MB, 6 PNG-Maps, float32-Vertices. Das ist unsere Basis.
Die erste häufige Falle liegt genau hier: Blender exportiert standardmäßig ungenutzte Meshes und verborgene Hilfsobjekte ebenfalls. Vor dem Export
File > Clean Up > Purge Orphansausführen und im Outliner nur die zu exportierenden Objekte auswählen.
Die End-to-End-Pipeline, Gesamtbild
Die ganze Linie zeichnen, damit Sie ein mentales Bild haben:
Blender-Quelldatei
│ .glb exportieren (float32 + PNG) 50 MB
▼
[1] Dedup + doppelte Vertices verschweißen (gltf-transform) ~45 MB
│
[2] Vertex-Kompression: MeshOpt (gltfpack / gltf-transform) ~30 MB
│
[3] Texturkompression: PNG → KTX2 (ETC1S/UASTC) ~6 MB
│
[4] (optional) Geometrie-Vereinfachung LOD (simplify) ~4-5 MB
▼
Final model-final.glb ~5 MB
│
Engine-Laden (Three.js / Babylon.js) → Laufzeit-Transcode → Live
Die Zahlen jedes Schritts werden unten in Tabellen live verfolgt.
Toolchain: welche wählen
Es gibt mehrere Kompressions-Werkzeuge; hier ein Vergleich, damit Sie nicht falsch wählen:
| Werkzeug | Stärke | Schwäche | Gut für |
|---|---|---|---|
| gltf-transform | Allrounder, Texturen+Vertices in einem Abwasch; API-fähig, skriptbar | Top-Verhältnis unter Spezialwerkzeugen | Empfohlenes Hauptwerkzeug für die meisten Szenarien |
| gltfpack | Vertex-Profi, nativ MeshOpt | Schwache Texturkompression | Vertex-dicht, feine MeshOpt-Kontrolle |
| toktx | Professionellste Texturkompression, meisten Parameter | Nur Texturen, nicht ganze Modelle | Einzeltextur-Feintuning |
| gltf-pipeline | Veteran, unterstützt Draco | Inaktive Wartung, wenig Features | Bestehende Draco-Legacy-Projekte |
| Online-Werkzeuge (gltf.report) | Null-Installation | Nicht für Automatisierung/Masse | Experimente, einmalige Aufgaben |
Hauptempfehlung: den ganzen Ablauf mit gltf-transform fahren; bei Bedarf mit gltfpack Vertices, mit toktx Einzeltexturen nachschärfen. Alle Schritte unten basieren auf gltf-transform.
Schritt 1: Dedup + Verschweißen
Modelle haben oft doppelte Vertices, ungenutzte Knoten und Materialien. Erst einmal reinigen.
gltf-transform optimize model.glb step1.glb --weld --prune
| Stufe | Dateigröße | VRAM | Änderung |
|---|---|---|---|
| Basis | 50 MB | ~520 MB | — |
| Step 1 Dedup | 45 MB | ~520 MB | -5 MB (VRAM unverändert, da Texturen noch da) |
VRAM bewegte sich kaum – wie erwartet. Dedup spert hauptsächlich Vertices und Struktur; Texturen sind der VRAM-Schwergewichtler.
Schritt 2: Vertex-Kompression MeshOpt
gltf-transform optimize step1.glb step2.glb --meshopt --weld --prune
--meshopt quantisiert Vertices auf 16 Bit und wendet MeshOpt-verlustfreie Kodierung an und fügt automatisch die EXT_meshopt_compression-Erweiterung hinzu.
| Stufe | Dateigröße | VRAM | Änderung |
|---|---|---|---|
| Step 1 | 45 MB | ~520 MB | — |
| Step 2 + MeshOpt | 30 MB | ~520 MB | -15 MB (Vertex-Anteil) |
VRAM noch ~520 MB? Richtig – denn Vertices sind ein kleiner Anteil des VRAM (10-20 %); sie zu schneiden hat begrenzten VRAM-Effekt. Das echte VRAM-Monster sind Texturen, als Nächstes behandelt.
Schritt 3: Texturkompression PNG → KTX2
Dieser Schritt ist der König der Kosten-Nutzen.
gltf-transform optimize step2.glb step3.glb \
--texture-compress basisu \
--meshopt --weld --prune
--texture-compress basisu erkennt jede Map automatisch: Farb-Maps (albedo, emissive) → ETC1S; Daten-Maps (normal, roughness, metallic, AO) → UASTC.
| Stufe | Dateigröße | VRAM | Änderung |
|---|---|---|---|
| Step 2 | 30 MB | ~520 MB | — |
| Step 3 + KTX2 | 6 MB | ~70 MB | -24 MB Datei / -450 MB VRAM |
Dieser Schritt ist der Wendepunkt der gesamten Pipeline:
- Datei fällt von 30 MB auf 6 MB
- VRAM fällt von 520 MB auf ~70 MB – weil die sechs 4096-Maps von „dekomprimierten Rohpixeln" zu „blockkomprimiert" wechseln, jede von ~87 MB auf ~11-14 MB
Der VRAM sinkt um eine Größenordnung – das ist der Schlüssel, ob es auf Mobil läuft.
Schritt 4: (optional) Geometrie-Vereinfachung
Wenn Sie noch kleiner wollen und die Szene eine Verringerung der Vertex-Präzision zulässt, fügen Sie Geometrie-Vereinfachung hinzu.
gltf-transform optimize step3.glb final.glb \
--texture-compress basisu \
--meshopt \
--simplify --simplify-ratio 0.5 \
--weld --prune
--simplify-ratio 0.5 bedeutet, etwa 50 % der Vertices zu behalten.
| Stufe | Dateigröße | VRAM | Änderung |
|---|---|---|---|
| Step 3 | 6 MB | ~70 MB | — |
| Step 4 + Vereinfachung 0.5 | 4.5 MB | ~70 MB | -1.5 MB (VRAM grob unverändert) |
Vereinfachung spart hauptsächlich Dateigröße; der VRAM-Effekt ist gering. Der Preis ist reduziertes Modelldetail – aus der Nähe sichtbar. E-Commerce-Produktseiten sollte man üblicherweise nicht übervereinfachen; Gebäude/große Szenen passen sehr gut.
Vollständige Effekt-Tabelle
Die vier Schritte übereinandergelegt für das Gesamtbild (basierend auf obigem Sample; Zahlen sind Größenordnungs-Illustration):
| Schritt | Dateigröße | VRAM | Kumulierte Reduktion |
|---|---|---|---|
| Basis (float32 + PNG) | 50 MB | ~520 MB | — |
| + Dedup & Verschweißen | 45 MB | ~520 MB | -10 % |
| + MeshOpt-Vertices | 30 MB | ~520 MB | -40 % |
| + KTX2-Texturen | 6 MB | ~70 MB | -88 % Datei / -87 % VRAM |
| + Geometrie-Vereinf. (0.5) | 4.5 MB | ~70 MB | -91 % Datei |
Fazit: Texturkompression liefert den ganz überwiegenden Anteil der Größen- und VRAM-Gewinne. Vertex-Kompression ist das Icing; Texturkompression ist die Rettung. Das deckt sich vollständig mit der These des ersten Artikels – Texturen sind 80 % der Größe, also ist ihre Optimierung am rentabelsten.
Ein-Befehl-Version: bequemer Ein-Klick
Wenn Sie nicht schrittweise vorgehen wollen, alle Optimierungen auf einmal:
gltf-transform optimize model.glb model-final.glb \
--texture-compress basisu \
--meshopt \
--simplify --simplify-ratio 0.5 \
--weld --prune
Dieser eine Befehl = Dedup + Verschweißen + Vertex-MeshOpt + Textur-KTX2 + Geometrie-Vereinfachung. Er reicht für 90 % der Szenarien; die Schritte dienen vor allem dem Verständnis und dem Tuning.
Automatisierungs-Skript: wiederverwendbar
Den Ablauf in ein Skript kapseln, das sich in den Build einbauen lässt. Dieses Skript gibt pro Zielplattform eine andere Version aus und druckt den Effekt jedes Schritts.
// scripts/compress-model.mjs
import { optimize } from "@gltf-transform/functions";
import { NodeIO } from "@gltf-transform/core";
import { KHRONOS_EXTENSIONS } from "@gltf-transform/extensions";
import { filesize } from "filesize";
const io = new NodeIO().registerExtensions(KHRONOS_EXTENSIONS);
// Kompressionsstrategien je Plattform
const PROFILES = {
mobile: {
textureCompression: "basisu",
meshCompression: "meshopt",
simplify: { ratio: 0.5 },
weld: true,
prune: true,
},
vr: {
textureCompression: "basisu",
meshCompression: "meshopt",
// VR-Nahansicht, keine Vereinfachung
simplify: null,
weld: true,
prune: true,
},
desktop: {
textureCompression: "webp",
meshCompression: "meshopt",
simplify: null,
weld: true,
prune: true,
},
};
async function compress(inputPath, profileName) {
const cfg = PROFILES[profileName];
const doc = await io.read(inputPath);
const before = Buffer.byteLength(await io.writeBinary(doc), "utf8");
await optimize(doc, {
textureCompression: cfg.textureCompression,
meshCompression: cfg.meshCompression,
simplify: cfg.simplify ?? undefined,
weld: cfg.weld,
prune: cfg.prune,
});
const bytes = await io.writeBinary(doc);
const outPath = inputPath.replace(/\.glb$/, `-${profileName}.glb`);
await io.write(outPath, doc);
const after = bytes.byteLength;
console.log(
`${profileName.padEnd(8)} ${filesize(before)} → ${filesize(after)} ` +
`(${Math.round((1 - after / before) * 100)}% smaller) → ${outPath}`
);
}
// Verwendung: node scripts/compress-model.mjs path/to/model.glb
const input = process.argv[2];
for (const profile of Object.keys(PROFILES)) {
await compress(input, profile);
}
Ins Projekt einbauen:
node scripts/compress-model.mjs public/models/model.glb
# mobile 50 MB → 4.5 MB (91 % kleiner) → model-mobile.glb
# vr 50 MB → 6.2 MB (87 % kleiner) → model-vr.glb
# desktop 50 MB → 11 MB (78 % kleiner) → model-desktop.glb
Das Frontend lädt zur Laufzeit einfach die passende Version pro Gerät.
Möchten Sie diese Pipeline nicht selbst bauen? Any3Ds Online-Tool erledigt alles Obige in einem Aufwasch – GLB hochladen, automatisch Textur-KTX2 + Vertex-MeshOpt laufen lassen und komprimierte Versionen pro Plattform ausgeben, ohne lokalen Toolchain-Aufwand.
Häufige Fallstricke FAQ
Modell wird schwarz / Texturen nach Kompression nicht angezeigt
- 99 % Farbraum: einer Farb-Map fehlt sRGB. In Three.js
texture.colorSpace = THREE.SRGBColorSpace. - Bei toktx Farb-Maps
--srgbvergessen.
Beleuchtung nach Normal-Map-Kompression falsch
- Normal-Map nutzte ETC1S; auf UASTC wechseln.
- Normal-Map ist DirectX-Stil (Grün-Kanal nach unten); Engine will OpenGL-Stil, G-Kanal umkehren.
Mobil-Laden hängt beim First Paint
- Prüfen, ob der Draco-Decoder-wasm geladen wird (zusätzlicher Request). Auf Mobil MeshOpt bevorzugen.
- KTX2-Transcoder-Pfad falsch konfiguriert; Transcode schlägt fehl und fällt auf CPU-Dekodierung zurück.
Komprimierte Datei wurde größer
- Map zu klein (< 128 px); KTX2 lohnt sich nicht – Blockkompression hat feste Overhead-Kosten.
- Modell war schon einmal komprimiert; ein zweiter Durchgang bringt keinen Gewinn (sogar negativ).
Modell bricht nach Vereinfachung
--simplify-ratiozu niedrig; auf 0.7-0.8 erhöhen.- Vereinfachung ist freundlich zu harten Oberflächen (Maschinen, Architektur) und bricht bei organischen Kurven (Charakteren) leicht.
KTX2 lädt in manchen Browsern nicht
- Alter Safari / alte WebView unterstützen es nicht. PNG/WebP-Fallback bereithalten oder über das
fallback-Feld vonKHR_texture_basisuein Sicherheitsnetz bieten.
Serien-Spickzettel
Das Wesen aller sechs Artikel in einer Tabelle kondensiert – bookmarken.
Größen-Zusammensetzung
| Bestandteil | Anteil | Optimierungs-Werkzeug |
|---|---|---|
| Textur-Maps | 70-85 % | KTX2 (größter Gewinn) |
| Vertex-Daten | 10-20 % | MeshOpt / Quantisierung / Draco |
| Animationsdaten | 0-15 % | Keyframes reduzieren / komprimieren |
| Sonstiges | < 2 % | Dedup |
VRAM-Formel
VRAM traditioneller Formate = Breite * Höhe * 4 Bytes * 1.333 (mit Mipmaps)
KTX2 blockkomprimierter VRAM ≈ obiges / 4 (ETC1S) oder / 2 (UASTC)
Vertex-Kompressions-Auswahl
| Szenario | Empfehlung |
|---|---|
| Null-Abhängigkeit, am einfachsten | Reine Quantisierung (KHR_mesh_quantization) |
| Ausgewogener Web-Erstfavorit | MeshOpt |
| Max-Verhältnis, Decode-Wartezeit ok | Draco |
| Mini Program / paketempfindlich | Reine Quant. / MeshOpt; Draco vermeiden |
Texturkompressions-Auswahl
| Map-Typ | Empfohlene Kodierung |
|---|---|
| albedo / emissive (Farbe) | KTX2 ETC1S |
| normal / roughness / metallic / AO (Daten) | KTX2 UASTC |
| Desktop-Web, Download-Geschwindigkeit | WebP / AVIF |
| Kleine Maps (< 128 px) | PNG belassen, kein KTX2 |
Ein-Klick-Befehl
# Volle Optimierung (Textur + Vertex + Vereinfachung)
gltf-transform optimize model.glb model-final.glb \
--texture-compress basisu --meshopt \
--simplify --simplify-ratio 0.5 --weld --prune
Plattform-Spickzettel
| Plattform | Textur | Vertex |
|---|---|---|
| Desktop-Web | WebP / KTX2 | MeshOpt |
| Mobil-Web | KTX2 Pflicht | MeshOpt |
| VR | KTX2 Pflicht | MeshOpt + LOD |
| Mini Program | KTX2 / WebP | MeshOpt / Quantisierung |
| Große Szene | KTX2 Pflicht | MeshOpt + Draco + LOD |
Serien-Rückblick
Sechs Artikel geschafft; zusammengefügt eine vollständige Kette:
- Warum so schwer: Größen-Zusammensetzung und die VRAM-Wahrheit klären
- Drei Waffen der Vertex-Kompression: Prinzipien und Wahl von Quantisierung, MeshOpt, Draco
- Das Textur-VRAM-Problem: warum PNG/JPG in den Augen der GPU schuldig sind
- KTX2 in der Praxis: ETC1S/UASTC-Auswahl, Toolchain, Engine-Laden
- Auswahl-Leitfaden: ein Entscheidungsrahmen nach Plattform/Szenario
- Dieser Artikel: End-to-End-Pipeline, von Blender bis Live
Der Kern ist ein Satz: erst den Flaschenhals durchdenken (Download/VRAM/Framerate), dann Werkzeuge wählen; Texturkompression bringt die größte Rendite, Vertex-Kompression ist Icing; verschiedene Plattformen, verschiedene Schicksale – keine Pauschallösung.
Mit dem Skript und Spickzettel dieses Artikels sollte es ein reproduzierbarer Weg sein, Ihr Modell von 50 MB auf 5 MB und den VRAM von 520 MB auf 70 MB zu bringen. Der Rest ist nur noch Tun.