Skip to content

So optimierst du GLB-Dateien für das Web: Draco, Meshopt und KTX2 (2026) ​

Zuletzt aktualisiert: September 2026.

Eine große Schatztruhe wird durch ein Rohr in eine winzige Kopie ihrer selbst gepresst

Um eine GLB-Datei für das Web zu optimieren, gehst du in dieser Reihenfolge vor: Verkleinere zuerst die Texturen (begrenze sie auf 1024 oder 2048 und kodiere sie für eine kleinere Downloadgröße als WebP oder für weniger GPU-Speicherverbrauch als KTX2), quantisiere die Vertexdaten, komprimiere die Geometrie mit Meshopt (oder mit Draco, wenn die letzten paar Hundert Kilobyte wichtiger sind als die Dekodierungszeit), vereinfache das Mesh, falls die Dreiecksanzahl noch immer absurd hoch ist, und bereinige, dedupliziere und verbinde anschließend den Rest. Ein Befehl erledigt den größten Teil davon: gltf-transform optimize in.glb out.glb --texture-compress webp. Die Reihenfolge ist wichtig, weil Texturen üblicherweise mindestens 80 Prozent der Datei und den gesamten Videospeicherbedarf ausmachen.

Kurzantwort ​

  • Texturlastiges Modell (die meisten Modelle): Verkleinere die Texturen auf 1024 oder 2048 und führe dann gltf-transform webp aus. Wenn es auf Smartphones ruckelt oder abstürzt, konvertiere sie stattdessen zu KTX2 – im Browser mit dem KTX2-Kompressor oder mit gltf-transform etc1s/uastc.
  • Geometrielastiges Modell (Scans, CAD, KI-generiert): Führe gltf-transform simplify und anschließend meshopt aus. Draco komprimiert etwas stärker, dekodiert aber langsamer und benötigt einen zehnmal größeren Decoder.
  • Animierter Charakter: Meshopt, nicht Draco. Draco lässt Animationsspuren und Morph-Targets unangetastet.
  • Die Datei muss in einer Engine geöffnet werden, über die du keine Kontrolle hast: gltf-transform quantize. Kein Decoder, nur KHR_mesh_quantization, das von jedem hier genannten Loader unterstützt wird.
  • Kein Terminal: Der GLB-Optimierer führt Bereinigung, Verschweißen, Verbinden, Vereinfachung, Texturverkleinerung zu WebP und Meshopt in deinem Browser aus und zeigt nach jedem Schritt die Dateigröße an.

Kurzübersicht ​

Nur QuantisierungMeshoptDraco
ErweiterungKHR_mesh_quantizationEXT_meshopt_compression (+ Quantisierung)KHR_draco_mesh_compression
Was komprimiert wirdVertexattribute (weniger Bits)Vertices, Indizes, Morph-Targets, AnimationenNur Dreiecksmesh-Geometrie
Größe unseres 28-MB-Testmodells22,8 MB (8,1 MB gzip-komprimiert)5,1 MB (3,3 MB gzip-komprimiert)2,6 MB (2,5 MB gzip-komprimiert)
DecoderKeiner32-KB-JS-Modul mit eingebettetem WASM192 bis 286 KB WASM plus 58-KB-Wrapper, 719-KB-JS-Fallback
DekodierungsgeschwindigkeitSofort, die GPU liest die Daten direktLaut Spezifikation etwa 1 GB/s mit WASM SIMDLaut glTF-Transform-Dokumentation deutlich langsamer als Meshopt
Benötigt gzip/brotli auf dem ServerHilft erheblichJa, dafür entwickeltGeringer Gewinn
Loaderthree.js, Babylon.js, PlayCanvas, glTFastthree.js r122+, Babylon.js 5.0+, glTFast (zusätzliches Paket), nicht PlayCanvasthree.js, Babylon.js, PlayCanvas, glTFast (zusätzliches Paket)

Dieselben Zahlen als Balken, ergänzt um die gltfpack- und simplify-Ergebnisse aus unserem Vergleichstest.

Ein Modell, alle Codecs28,7 MB große TRELLIS.2-Ausgabe, 978.226 Dreiecke. gltf-transform 4.5.0 und gltfpack 1.2.Rohdateigzip-komprimiertOriginalfloat32-Geometrie, 1,1 MB Texturen28,7 MBquantizeKHR_mesh_quantization, kein Decoder22,8 MB8,1 MBmeshopt --level highEXT_meshopt_compression5,1 MB3,3 MBgltfpack -ccMeshopt, stärkerer Komprimierungsmodus4,4 MB3,1 MBdracoKHR_draco_mesh_compression2,6 MB2,5 MBsimplify --ratio 0.25244.556 Dreiecke8,1 MBvor der Komprimierung; jeder Codec oben kann noch angewendet werdenDie optimize-Standardwerte (ratio 0, error 0.0001) reduzierten dieselbe Datei auf 6.582 Dreiecke.
Draco gewinnt bei der Dateigröße, doch gzip bringt dabei fast nichts, während Meshopt und quantisierte Ausgaben auf die Serverkomprimierung angewiesen sind. Die Vereinfachung ist der einzige Schritt, der die Dreiecksanzahl verändert. Die 8,1 MB sind daher ein neuer Ausgangspunkt und nicht das Endergebnis.

Wo die Bytes in einer GLB-Datei stecken ​

Führe zuerst gltf-transform inspect model.glb aus. Der Befehl listet jedes Mesh mit Vertexanzahl und Attributtypen, jede Textur mit ihrer kodierten Größe und gpuSize sowie jede Animation mit ihrer Keyframe-Anzahl auf. Die Zahlen in diesem Leitfaden stammen aus der Werkzeugdokumentation und den Erweiterungsspezifikationen sowie aus einem Vergleichstest, den wir diese Woche mit gltf-transform 4.5.0 und gltfpack 1.2 anhand zweier echter Dateien durchgeführt haben. Sie zeigen die beiden typischen Fälle, denen du begegnen wirst.

Ein 2,2 MB großes Sketchfab-Objekt (ein Low-Poly-Becher) hatte 680 Dreiecke und 39 KB Geometrie. Die übrigen 2,18 MB entfielen auf drei PNGs mit 1024×1024 Pixeln. Texturen machten damit 98 Prozent der Datei aus, und inspect schätzte für jede Textur mit Mipmaps einen VRAM-Verbrauch von 5,59 MB. Das ist der typische Fall bei handgefertigten Assets.

Bei einer 28,7 MB großen TRELLIS.2-Ausgabe war es umgekehrt: 978.226 Dreiecke und 27,5 MB float32-Geometrie bei nur 1,1 MB Texturen. Diese beiden Texturen waren jedoch 4096×4096 Pixel groß, was laut inspect jeweils 89,5 MB VRAM beansprucht. Modelle aus dem 3D-Modellgenerator und vergleichbaren Werkzeugen kommen regelmäßig in diesem Zustand an: dicht und mit überdimensionierten Texturen. Deshalb benötigen sie neben den Texturschritten auch die Geometrieschritte.

Wo die Bytes steckenKodierte Größe nach Inhalt. Der GPU-Speicher ist eine separate Zahl rechts.TexturenGeometriealles andere (Animationen, JSON, Skins)Typisches handgefertigtes AssetTexturen, mindestens 80 Prozentalles anderetypische Verteilung2,2-MB-Sketchfab-Becher, 680 Dreieckedrei 1024x1024-PNGs, 2,18 MB (98 Prozent)Geometrie 39 KB5,59 MB VRAMpro Textur, mit Mipmaps28,7-MB-TRELLIS.2-Ausgabe, 978.226 Dreieckefloat32-Geometrie, 27,5 MBTexturen 1,1 MB, zwei mit 4096x409689,5 MB VRAMpro Textur, mit Mipmaps
Die typische Zeile zeigt die Faustregel, die beiden anderen zeigen die echten Dateien aus dem Vergleichstest. Beachte die rechte Spalte: Die 1024er-Texturen des Bechers und die 4096er-Texturen von TRELLIS.2 sind auf dem Datenträger beide klein, unterscheiden sich beim Videospeicherverbrauch jedoch drastisch.

Beachte, dass die kodierte Texturgröße und die GPU-Größe nicht miteinander zusammenhängen. Eine 4 MB große PNG-Datei und eine 200 KB große WebP-Datei desselben Bildes mit 2048×2048 Pixeln belegen im Videospeicher beide ungefähr 22 MB – Rohpixel plus Mipmaps. Nur KTX2 verändert diesen Wert.

Die folgenden sechs Schritte werden in dieser Reihenfolge ausgeführt, weil jeder Schritt die Datenmenge reduziert, die der nächste verarbeiten muss.

Die richtige ReihenfolgeDer größte Gewinn zuerst. Größen basieren auf dem 28,7-MB-Testmodell.1Texturen: auf 1024 oder 2048 begrenzen, dann WebP oder KTX2Meist 80 Prozent oder mehr der Datei und der gesamte Grafikspeicher2Quantisieren28,7 MB auf 22,8 MB (8,1 MB gzip), kein Decoder, jeder Loader liest es3Meshopt oder Draco5,1 MB (3,3 gzip) oder 2,6 MB (2,5 gzip), Decoder auf dem Client4Vereinfachen978.226 auf 244.556 Dreiecke bei Faktor 0,25, auf Spieldistanz identisch5Bereinigen, deduplizieren, zusammenführen, instanziierenKostenlose Gewinne: Unreferenziertes entfernen, 200 Draw Calls auf wenige reduzieren6Animation: neu abtastenEntfernt Keyframes auf der Linie zwischen Nachbarn, praktisch verlustfrei
Folge den Zahlen von oben nach unten. In den Schritten 1 und 4 stecken die meisten Bytes, Schritt 2 ist nur bei einem riesigen einzelnen Mesh sichtbar, und bei Schritt 5 ist mit einem geriggten Charakter Vorsicht geboten, da das Zusammenführen Teile verschmilzt, die sich bewegen sollen.

Schritt 1: Texturen ​

Zwei getrennte Probleme, zwei getrennte Lösungen.

Die Downloadgröße wird durch Skalieren und erneutes Kodieren reduziert. Nur wenige Props benötigen mehr als 1024×1024, und selbst ein Hauptcharakter braucht selten mehr als 2048. gltf-transform resize --width 1024 --height 1024 begrenzt die Abmessungen, ohne jemals hochzuskalieren, und gltf-transform webp kodiert mit sharp neu. Beim Becher verkleinerte allein WebP die Datei von 2,23 MB auf 246 KB. Wurde sie zuerst auf 512 skaliert, sank sie auf 96 KB – ohne sichtbare Veränderung bei einem Prop dieser Größe. WebP benötigt EXT_texture_webp, das von Web-Engines gelesen wird, aber nicht von Unitys glTFast (laut dessen Funktionstabelle wird es „nicht unterstützt werden“).

GPU-Speicherbedarf und Uploadzeit lassen sich nur mit KTX2 samt Basis-Universal-Superkompression reduzieren. Dadurch bleibt die Textur bis in den VRAM hinein in einem GPU-Blockformat und benötigt vier- bis achtmal weniger Speicher als rohes RGBA. KTX2 erhält weiter unten einen eigenen Abschnitt, weil die Einstellungen entscheidend sind.

Eine Warnung aus dem Vergleichstest: gltf-transform optimize verwendet standardmäßig --texture-compress auto, wodurch Texturen erneut in ihrem ursprünglichen Format kodiert werden. Beim Becher wurden die PNGs dadurch größer, und die Datei wuchs von 2,2 MB auf 2,8 MB. Gib webp oder ktx2 ausdrücklich an.

Schritt 2: Quantisieren ​

Bei der Quantisierung wird jedes Vertexattribut mit weniger Bits gespeichert. Eine Position wird statt mit drei 32-Bit-Gleitkommazahlen mit drei 16-Bit-Ganzzahlen gespeichert, wobei Skalierung und Versatz in die Knotentransformation integriert werden (oder bei geskinnten Meshes in inverseBindMatrices). Laut der Spezifikation KHR_mesh_quantization benötigt ein typischer Vertex dadurch ungefähr 20 statt 48 Byte. Es handelt sich um eine ratifizierte Khronos-Erweiterung ohne Decoder: Die GPU liest die Ganzzahlattribute direkt, sodass quantisierte Dateien sowohl im VRAM als auch bei der Übertragung weniger Platz benötigen.

Die Standardwerte von glTF-Transform sind 14 Bit für Positionen, 10 für Normalen und Tangenten, 12 für UVs sowie 8 für Farben und Gewichte. Bei gltfpack sind es 14, 8, 12 und 8. Beides ist unsichtbar, außer bei einem riesigen einzelnen Mesh, bei dem 14 Bit über die gesamte Ausdehnung zu sichtbarer Facettierung führen können. Für sich allein bringt die Quantisierung nur mäßige Einsparungen: Unser 28-MB-Modell schrumpfte roh auf 22,8 MB und gzip-komprimiert auf 8,1 MB. Ihre eigentliche Aufgabe besteht darin, die erste Hälfte von Meshopt zu bilden – oder eine sichere Ausgabe bereitzustellen, wenn der Ziel-Loader unklar ist. Draco quantisiert intern mit denselben Standardwerten, führe quantize also nicht vor draco aus.

Schritt 3: Meshopt oder Draco ​

Beide sind verlustbehaftete Geometrie-Codecs, die vor dem GPU-Upload in einfache Buffer dekodieren. Daher sorgt keiner von beiden für ein schnelleres Rendering des Modells. Sie verkleinern den Download. Die Unterschiede liegen darin, was sie komprimieren, wie schnell sie dekodieren und wie groß der mitgelieferte Decoder ist.

Meshopt (EXT_meshopt_compression) arbeitet auf der Ebene der bufferViews, sodass Vertexattribute, Indizes, Morph-Target-Deltas und Animations-Keyframes allesamt komprimiert werden. Es ist dafür ausgelegt, auf der Quantisierung aufzubauen und unter gzip oder Brotli zu arbeiten: Der Codec bringt die Bytes in eine regelmäßige Form, und der universelle Kompressor des CDNs übernimmt den Rest. Die Spezifikation nennt mit WebAssembly SIMD Dekodiergeschwindigkeiten von etwa 1 GB/s, und der Decoder von three.js besteht aus einem einzigen 32-KB-Modul. Beim Testmodell: 5,1 MB roh, 3,3 MB gzip-komprimiert, mit dem Standardwert --level high.

Draco (KHR_draco_mesh_compression) komprimiert ausschließlich Dreiecks-Mesh-Primitiven. Animationen, Morph Targets, Punkte und Linien werden unverändert übernommen. Es komprimiert stärker – auf 2,6 MB beim selben Modell – und gzip bringt kaum weitere Vorteile, weil die Ausgabe bereits sehr dicht ist. Der Preis dafür sind Dekodierzeit und Decodergröße: In der Dokumentation von glTF-Transform steht ausdrücklich, dass Meshopt erheblich schneller dekodiert. Der von three.js mitgelieferte WASM-Decoder ist 286 KB groß (192 KB beim Build des glTF-Branches), hinzu kommen ein 58-KB-Wrapper und ein 719 KB großes JavaScript-Fallback. Draco ändert außerdem die Reihenfolge und kann die Anzahl der Vertices verändern.

Daher gilt: Meshopt für alles Animierte, alles mit Morph Targets, alles, bei dem eine kurze Ladezeit auf dem Smartphone entscheidend ist, und alles, was mit aktiviertem Brotli ausgeliefert wird. Draco eignet sich, wenn das Asset ein statisches Mesh ist, die Geometrie den Großteil ausmacht und 20 bis 30 Prozent weniger Übertragungsvolumen ein langsameres erstes Frame wert sind. Unsicher? Nimm Meshopt. gltfpacks -cc (Meshopt im stärkeren Modus) erreichte bei derselben Datei 4,4 MB roh und 3,1 MB gzip-komprimiert.

Schritt 4: Vereinfachen ​

Wenn das Modell nach der Komprimierung noch immer groß ist, hat es zu viele Dreiecke – und kein Codec kann das beheben. Beide Werkzeuge verwenden den Simplifier von meshoptimizer. Dieser erhält einen Zielfaktor und eine Fehlergrenze und stoppt, sobald einer der beiden Werte erreicht ist.

gltf-transform simplify --ratio 0.25 --error 0.01 zielt auf 25 Prozent der Vertices ab, wobei die Abweichung höchstens 1 Prozent des Mesh-Radius betragen darf. Beim Modell mit 978.000 Dreiecken ergab das 244.556 Dreiecke und vor der Komprimierung 8,1 MB – auf Spieldistanz sah es identisch aus. Die Standardwerte von optimize sind aggressiver, als man vermuten würde: --simplify-ratio 0 zusammen mit --simplify-error 0.0001 bedeutet „innerhalb einer Fehlergrenze von 0,01 Prozent so viel wie möglich entfernen“. Beim selben übermäßig tessellierten Modell reduzierte dies die Zahl auf 6.582 Dreiecke, weil der Generator fast eine Million Dreiecke für ebene Flächen verwendet hatte. Verschweiße die Vertices vor dem Vereinfachen (optimize tut dies), denn getrennte Vertices hindern den Simplifier an Nähten.

gltfpacks -si 0.25 verfolgt denselben Ansatz, mit -se 0.01 als standardmäßiger Fehlergrenze, -sa, um den Zielfaktor unabhängig von der Qualität zu erreichen, und -slb, um Rand-Vertices zu fixieren, damit bei modularen Meshes keine Lücken entstehen. Hard-Surface-Props vertragen problemlos eine Reduktion um 50 Prozent, gescannte und KI-generierte Meshes meist sogar um 90 Prozent. Bei geriggten Charakteren ist im Bereich der Gelenke Vorsicht geboten, da beim Zusammenlegen von Vertices auch Skin-Gewichte zusammengelegt werden.

Schritt 5: Bereinigen, deduplizieren, zusammenführen, instanziieren ​

Diese Schritte bringen kostenlose Einsparungen, und optimize führt sie alle aus. prune entfernt Materialien, Texturen, Accessors und Knoten, auf die nichts verweist, und wandelt einfarbige Texturen in Materialfaktoren um. dedup führt identische Accessors und Texturen zusammen, die ein Exporter doppelt geschrieben hat. flatten reduziert die Hierarchie und join führt Meshes mit demselben Material zusammen – dadurch werden aus 200 Draw Calls nur noch wenige. instance wandelt wiederholte Meshes (ab 5 Kopien) in EXT_mesh_gpu_instancing um, und palette führt Materialien zusammen, die sich nur in der Farbe unterscheiden.

Verwende join oder flatten nicht bei einem geriggten Charakter oder bei Objekten, deren Teile im Spiel einzeln bewegt werden, da diese Teile sonst in einem einzigen Mesh aufgehen. Der Ausweg bei gltfpack ist -kn (benannte Knoten beibehalten) und -km (benannte Materialien beibehalten).

Schritt 6: Animation ​

Exporter backen häufig auf jedem Frame einen Keyframe. gltf-transform resample entfernt Keyframes, die auf der Linie zwischen ihren Nachbarn liegen (standardmäßig mit einer Toleranz von 1e-4), was in der Praxis verlustfrei ist. gltfpacks -af 30 tastet jede Spur mit 30 Hz neu ab und quantisiert Translationen mit 16 Bit, Rotationen mit 12 und Skalierungen mit 16 (-at, -ar, -as), bevor Meshopt sie komprimiert. Bei einem typischen Charakter mit einigen wenigen Clips ist dies nur ein kleiner Schritt. Bei einer Bewegungsbibliothek kann dadurch der Großteil der Bytes eingespart werden.

Die Befehlszeilen ​

Die CLI von glTF-Transform wird mit npm install --global @gltf-transform/cli installiert oder über npx @gltf-transform/cli ausgeführt. Alles in einem Schritt:

bash
gltf-transform optimize in.glb out.glb --texture-compress webp --texture-size 1024

Damit werden in dieser Reihenfolge dedup, instance, palette, flatten, join, weld, simplify (Faktor 0, Fehler 0,0001), resample, prune, sparse, Texturkomprimierung mit einer Obergrenze von 1024 und Meshopt mit Stufe high ausgeführt. Ergänze --compress draco für Draco, --compress quantize nur für Quantisierung, --no-join --no-flatten für geriggte oder beweglich gegliederte Modelle, --simplify false, wenn die Silhouette wichtiger als die Dateigröße ist, und --texture-compress ktx2, wenn KTX-Software installiert ist.

Die einzelnen Schritte, wenn du mehr Kontrolle benötigst:

bash
gltf-transform inspect in.glb
gltf-transform resize in.glb a.glb --width 1024 --height 1024
gltf-transform webp a.glb b.glb --quality 80
gltf-transform weld b.glb c.glb
gltf-transform simplify c.glb d.glb --ratio 0.5 --error 0.001
gltf-transform meshopt d.glb out.glb --level high

Ersetze die letzte Zeile durch gltf-transform draco d.glb out.glb (--encode-speed und --decode-speed reichen von 0 bis 10, Standardwert 5; niedrigere Werte erzeugen kleinere Dateien) oder gltf-transform quantize d.glb out.glb.

gltfpack wird mit npm install -g gltfpack installiert oder als native Binärdatei aus den meshoptimizer-Releases bezogen, was die README für große Dateien empfiehlt. Die Standardeinstellungen quantisieren bereits, optimieren die Vertexreihenfolge für den GPU-Cache und führen Meshes zusammen:

bash
gltfpack -i in.glb -o out.glb -cc -si 0.5 -tw -tl 1024 -kn

-cc aktiviert Meshopt im Modus mit höherer Kompression (-c ist der schnelle Modus, -cf ergänzt einen unkomprimierten Fallback für Loader ohne Decoder). -si 0.5 halbiert die Zahl der Dreiecke innerhalb von -se 0.01. -tw konvertiert Texturen in WebP, und -tl 1024 begrenzt ihre Größe. -kn behält benannte Knoten bei. Für KTX2 ersetzt du -tw durch -tc (ETC1S) oder -tc -tu (UASTC). Dafür ist ein gltfpack-Build erforderlich, in den Basis Universal eingebunden ist.

Wenn keine der beiden CLIs infrage kommt, führt das Browserwerkzeug dieselbe Abfolge aus.

GLB-Optimierungsseite, auf der ein 4,0 MB großer Beispielcharakter auf 676 KB schrumpft, mit der Größe nach jedem Schritt
Der Weg ohne Terminal: Bereinigen, Verschweißen, Zusammenführen, Vereinfachen, Texturen skalieren und in WebP umwandeln sowie Meshopt im Browser – mit einer Größenanzeige nach jedem Schritt, damit du siehst, welcher davon den Unterschied gemacht hat.

KTX2: ETC1S oder UASTC ​

KTX2 ist der Container von Khronos für GPU-Texturen. Mit der Superkompression von Basis Universal wird die Textur beim Laden in das vom Gerät unterstützte Blockformat transkodiert (BC auf Desktop-Systemen, ASTC oder ETC2 auf Mobilgeräten) und bleibt im Speicher komprimiert. Die glTF-Erweiterung ist KHR_texture_basisu. Basis hat zwei Modi. ETC1S ist der kompakte: Laut Basis-README benötigt er auf dem Datenträger ungefähr 0,3 bis 3 Bit pro Pixel und bietet einen JPEG-ähnlichen Qualitätsregler (1 bis 255, Standardwert 128). Im Speicher belegt er in Formaten wie BC1 und ETC1 4 Bit pro Pixel. Verwende ihn für die Grundfarbe von Requisiten. UASTC ist der Qualitätsmodus: 8 Bit pro Pixel im Speicher, eine Teilmenge von ASTC 4×4 mit 19 Modi und Qualitätsstufen von 0 bis 4 (Standardwert 2, was laut Hilfe von glTF-Transform 47,47 dB entspricht). UASTC-Dateien sind auf dem Datenträger groß, kombiniere sie daher mit Zstandard: Bei uastc verwendet glTF-Transform standardmäßig --zstd 18, und ktx create --zstd akzeptiert Werte von 1 bis 22.

Die Rechnung für eine 2048×2048-Textur mit Mipmaps: etwa 22 MB als RGBA8, etwa 5,6 MB als UASTC und etwa 2,8 MB als ETC1S, transkodiert in ein Format mit 4 bpp.

Drei Regeln sind entscheidend. Normal- und Daten-Maps benötigen UASTC und lineare Farbdaten. glTF-Transform warnt davor, dass RGB-Normal-Maps und Occlusion-/Roughness-/Metalness-Maps mit ETC1S schlecht aussehen können. Außerdem verlangt die Spezifikation, dass Farbtexturen als sRGB und Nicht-Farbdaten als linear gekennzeichnet werden. glTF-Transform legt das für jeden Slot automatisch fest. Im KTX2-Kompressor ist dies der sRGB-Schalter: ein für Farbe, aus für Normal- und Daten-Maps. Die Abmessungen müssen Vielfache von 4 sein, Zweierpotenzen werden empfohlen. Erzeuge Mipmaps. Laut Spezifikation sollte eine KTX2-Datei, die mit Mipmap-Minifizierung verwendet wird, die vollständige Pyramide enthalten. Andernfalls muss die Engine sie zur Laufzeit dekomprimieren und erzeugen. Mipmaps sind in glTF-Transform und im Browser-Tool standardmäßig aktiviert; bei ktx create verwendest du --generate-mipmap.

Die glTF-Transform-Befehle benötigen das ktx-Programm aus KTX-Software, Version 4.4.0 oder neuer:

bash
gltf-transform uastc in.glb a.glb --level 2 --zstd 18 --slots "{normalTexture,occlusionTexture,metallicRoughnessTexture}"
gltf-transform etc1s a.glb out.glb --quality 128

Wende zuerst UASTC auf die Daten-Slots und anschließend ETC1S auf den Rest an. Diese Aufteilung – ETC1S für Grundfarbe und Emission sowie UASTC für Normalen und ORM – ist die übliche Wahl.

Ergebnis laden ​

Jeder Codec außer Quantisierung benötigt auf dem Client einen Decoder.

three.js. GLTFLoader liest KHR_mesh_quantization und EXT_texture_webp ohne zusätzliche Einrichtung. Für die anderen Formate bindest du Decoder ein, die im Paket three unter examples/jsm/libs/ als draco/, basis/ und meshopt_decoder.module.js enthalten sind. Kopiere draco/ und basis/ in einen öffentlichen Pfad und verwende dann:

js
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js'
import { KTX2Loader } from 'three/addons/loaders/KTX2Loader.js'
import { MeshoptDecoder } from 'three/addons/libs/meshopt_decoder.module.js'

const draco = new DRACOLoader().setDecoderPath('/libs/draco/')
const ktx2 = new KTX2Loader().setTranscoderPath('/libs/basis/').detectSupport(renderer)
const loader = new GLTFLoader()
  .setDRACOLoader(draco)
  .setKTX2Loader(ktx2)
  .setMeshoptDecoder(MeshoptDecoder)

DRACOLoader wählt den WASM-Decoder, wenn der Browser ihn unterstützt, und greift andernfalls auf JavaScript zurück. Mit detectSupport(renderer) kann KTX2Loader das passende Transkodierungsziel für die GPU des Geräts auswählen.

Babylon.js. Der glTF-Loader unterstützt Draco, Meshopt (seit 5.0 ohne Einrichtung) und KTX2, indem er Decoder von https://cdn.babylonjs.com herunterlädt und sie in Web Workern ausführt. Für Self-Hosting legst du Tools.CDNBaseUrl fest oder konfigurierst die einzelnen Einstellungen: DracoDecoder.DefaultConfiguration (wasmUrl, wasmBinaryUrl, fallbackUrl), MeshoptCompression.Configuration.decoder.url und KhronosTextureContainer2.URLConfig für die KTX2-Transcoder. Bei npm enthält @babylonjs/ktx2decoder die Transcoder.

PlayCanvas. Draco wird mit dracoInitialize({ jsUrl, wasmUrl, numWorkers, lazyInit }) konfiguriert, und der Editor kann beim Import mit Draco komprimieren. KTX2 wird über basisInitialize({ glueUrl, wasmUrl, fallbackUrl }) eingerichtet. EXT_meshopt_compression wird in Engine 2.x nicht vom GLB-Parser unterstützt – die Funktionsanfrage von 2020 ist weiterhin offen. Wähle für PlayCanvas daher Draco oder eine Ausgabe, die nur quantisiert ist.

Unity. Der offizielle Importer ist glTFast (com.unity.cloud.gltfast). KHR_mesh_quantization funktioniert ohne zusätzliche Einrichtung, Draco benötigt com.unity.cloud.draco, KTX2 benötigt com.unity.cloud.ktx und Meshopt benötigt com.unity.meshopt.decompress. WebP wird bewusst nicht unterstützt; verwende daher für Unity als Zielplattform KTX2.

Zielwerte für ein mobiles Webspiel ​

Dafür gibt es keine Spezifikation, aber bestimmte Richtwerte sorgen dafür, dass Smartphones zuverlässig mitspielen. Halte die gesamte erste Szene bei der Übertragung unter etwa 10 MB und streame den Rest. Das Tutorial zum Streaming von Assets behandelt die Stufen und den erforderlichen Code. Halte den Textur-VRAM-Verbrauch unter 150 bis 200 MB; das entspricht vier oder fünf 2048er-Texturen als RGBA8 oder dreißig als ETC1S. Requisiten sollten unter 5.000 Dreiecken und eine Hauptfigur unter 30.000 bis 50.000 Dreiecken bleiben. Die Draw Calls sollten im niedrigen dreistelligen Bereich liegen. Verwende 1024er-Texturen für Requisiten und 2048 nur für Objekte, denen die Kamera nahekommt. Liefere GLBs mit aktiviertem Brotli oder gzip aus, da Meshopt und quantisierte Ausgaben darauf angewiesen sind.

Vor der Veröffentlichung überprüfen ​

Die Dateigröße ist der einfache Kennwert. Öffne das Ergebnis im GLB-Viewer und prüfe den Rest: Im Bereich „Erweiterungen“ siehst du, ob EXT_meshopt_compression, KHR_draco_mesh_compression oder KHR_texture_basisu tatsächlich in die Datei aufgenommen wurde. Der Tab „Texturen“ listet alle Texturen nach ihrem tatsächlichen VRAM-Verbrauch absteigend auf, und die Statusleiste zeigt die aktuellen Draw Calls sowie die Anzahl der Dreiecke. Prüfe anschließend Silhouetten und UV-Nähte in der Entfernung, aus der die Spielenden sie sehen, auf Vereinfachungsartefakte. Spiele außerdem alle Animationen ab, um sicherzustellen, dass beim Zusammenfügen keine Teile verbunden wurden, die sich separat bewegen sollen. Wenn die Quelldatei ursprünglich keine GLB-Datei war, verarbeite FBX oder OBJ zunächst mit dem FBX-zu-GLB-Konverter, damit du genau die Datei komprimierst, die später tatsächlich geladen wird.

GLB-Viewer-Seite mit einer Froschfigur und einer Übersicht zu Dreiecken, Draw Calls, Knochen und Geometriegröße
Öffne hier die komprimierte Ausgabe, um zu bestätigen, dass die Erweiterung tatsächlich in die Datei aufgenommen wurde. Lies anschließend die Draw Calls und die Anzahl der Dreiecke in der Statusleiste sowie den tatsächlichen VRAM-Verbrauch jeder Textur im Tab „Texturen“ ab.

Häufige Fragen ​

Wie reduziere ich die Größe einer GLB-Datei? ​

Führe gltf-transform inspect aus, um zu sehen, ob Texturen oder Geometrie den größten Anteil ausmachen. Sind es die Texturen, verkleinere sie auf 1024 oder 2048 und konvertiere sie in WebP oder KTX2. Ist es die Geometrie, vereinfache sie und komprimiere sie anschließend mit Meshopt oder Draco. gltf-transform optimize in.glb out.glb --texture-compress webp führt die gesamte Abfolge aus, und der browserbasierte GLB-Optimierer erledigt dies ohne Installation.

Draco oder Meshopt: Was ist besser? ​

Für die meisten Webspiele ist Meshopt besser geeignet. Es dekodiert wesentlich schneller, benötigt einen 32-KB-Decoder statt mehrerer Hundert Kilobyte WASM und komprimiert Animationen sowie Morph Targets, die Draco auslässt. Draco erzeugt bei statischen Meshes kleinere Dateien – bei unserem 28-MB-Testmodell waren es gzip-komprimiert 2,6 MB statt 3,3 MB – und wird von PlayCanvas unterstützt. Daher ist Draco die bessere Wahl, wenn das Asset ein statischer Scan ist und die Geometrie den größten Anteil der Datei ausmacht.

Was ist KTX2, und wie unterscheidet es sich von Basis? ​

Basis Universal ist der Komprimierungs-Codec mit den beiden Modi ETC1S und UASTC. KTX2 ist das Khronos-Containerformat, das mit Basis komprimierte Texturdaten sowie Mipmaps und Metadaten enthält. glTF referenziert es über KHR_texture_basisu. Ältere Pipelines verwendeten eine eigenständige .basis-Datei. Verwende .ktx2.

Sollte ich ETC1S oder UASTC verwenden? ​

ETC1S eignet sich für Grundfarben und alles, was nicht aus der Nähe betrachtet wird: kleine Dateien und 4 Bit pro Pixel im VRAM. Verwende UASTC für Normal-Maps, Roughness-/Metalness-/Occlusion-Maps und besonders wichtige Texturen. Aktiviere dabei die Zstandard-Superkomprimierung, damit die Downloadgröße vertretbar bleibt. Kennzeichne Farbtexturen als sRGB und Datentexturen als linear, da die Normalen sonst falsch schattiert werden.

Wie komprimiere ich glTF-Texturen? ​

Für eine kleinere Downloadgröße verwendest du zuerst gltf-transform resize und anschließend gltf-transform webp. Um GPU-Speicher zu sparen, verwendest du bei installierter KTX-Software gltf-transform etc1s oder uastc. Alternativ kannst du die PNG-Dateien im KTX2-Kompressor ablegen. Begrenze in beiden Fällen zuerst die Abmessungen: Eine 4096er-Textur benötigt als RGBA8 89 MB VRAM, und es gibt fast nie einen Grund, eine solche Textur in einem Browser auszuliefern.

Warum ist meine GLB-Datei für three.js auf Mobilgeräten zu groß? ​

Meist liegt es nicht an der Dateigröße, sondern am Texturspeicher. Vier 2048er-RGBA-Texturen belegen etwa 90 MB VRAM, noch bevor die Szene etwas gezeichnet hat. Smartphone-Browser beenden den Tab häufig, sobald der Verbrauch einige Hundert Megabyte überschreitet. Konvertiere die Texturen in KTX2, damit sie auf der GPU komprimiert bleiben, begrenze sie möglichst auf 1024 und rufe KTX2Loader.detectSupport(renderer) auf, damit sie in das Format des jeweiligen Geräts transkodiert werden.

Erledigt gltfpack dasselbe wie gltf-transform? ​

Größtenteils. gltfpack ist ein einzelnes natives Programm aus dem meshoptimizer-Projekt, das standardmäßig quantisiert, Vertices für den GPU-Cache neu anordnet, Meshes zusammenführt und mit Meshopt komprimiert. glTF-Transform ist eine Node-Bibliothek und CLI, die dieselben Operationen als separate, skriptfähige Schritte bereitstellt. Zusätzlich kann sie Draco-Ausgaben erzeugen, was gltfpack nicht unterstützt. Bei unserer Testdatei lagen die Meshopt-Ausgaben beider Werkzeuge innerhalb von etwa 10 Prozent voneinander.

Verwandte Themen ​