glTF-Laden in three.js
Lädt .gltf / .glb-Modelle, einschließlich komprimierter Geometrie (DRACO, Meshopt) und Texturen (KTX2), und spielt deren Animationsclips ab. Die Muster beziehen sich auf r187; ein bestehendes Projekt behält seine fixierte Version, es sei denn, der Benutzer bittet um ein Upgrade. glTF ist das bevorzugte Laufzeitformat: OBJ hat keine Szenengraphik oder Animation, und FBX ist im Browser aufwendig zu parsen.
Wann verwenden
- Importieren eines Modells oder Charakters, Untersuchen seiner Knotenhierarchie, Abspielen oder Überblenden von Clips, Erstellen vieler Kopien eines animierten Gegners oder Beheben eines Modells, das nicht angezeigt wird.
- Dateien sind
.gltf/.glb, oder Code importiertGLTFLoader,DRACOLoaderoderKTX2Loaderausthree/addons/loaders/.... - Nicht für Renderer, Kamera und Schleife (
threejs-scene-setup), Beleuchtung und Materialien des Modells (threejs-materials-lighting) oder Modellierungs- und Exporteinstellungen in einem DCC-Tool.
Arbeitsablauf
- Datei vor dem Schreiben des Loader-Codes inspizieren, wenn
gltf-transformverfügbar ist:npx @gltf-transform/cli inspect model.glblistet Meshes, Erweiterungen (z. B.KHR_draco_mesh_compression,EXT_meshopt_compression,KHR_texture_basisu), Clips und Texturgrößen auf. Jede aufgeführte Komprimierungserweiterung benötigt ihren angeschlossenen Decoder. - Mit
GLTFLoaderladen (loadAsyncin asynchronem Code). Das Ergebnis enthältgltf.scene, die WurzelObject3D, undgltf.animations, einAnimationClip[]. gltf.scenehinzufügen und einrahmen. glTF-Einheiten sind Meter; Namen und Grenzen protokollieren, um die Teile zu finden, die der Code steuern wird.- Ein
AnimationMixerpro animierter Wurzel, Aktionen ausmixer.clipAction(clip)undmixer.update(seconds)jedes Bild. - Decoder anhängen für die in Schritt 1 gefundenen Erweiterungen. Seit r185 finden
DRACOLoaderundKTX2Loaderihre gebündelten Decoder-Dateien ohne Pfadangabe. - Überprüfen mit Überprüfen.
Muster
1. Modell laden und einrahmen
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
const gltf = await new GLTFLoader().loadAsync('assets/robot.glb');
const root = gltf.scene;
scene.add(root);
const box = new THREE.Box3().setFromObject(root);
console.log('Größe (m):', box.getSize(new THREE.Vector3()).toArray());
console.log('Clips:', gltf.animations.map((c) => c.name));
2. Einen Clip abspielen
const timer = new THREE.Timer(); // THREE.Clock ist seit r183 veraltet
const mixer = new THREE.AnimationMixer(gltf.scene);
const run = THREE.AnimationClip.findByName(gltf.animations, 'Run') ?? gltf.animations[0];
mixer.clipAction(run).play();
renderer.setAnimationLoop(() => {
timer.update();
mixer.update(timer.getDelta()); // Sekunden, nicht Millisekunden
renderer.render(scene, camera);
});
3. Zwischen Clips überblenden
const actions = Object.fromEntries(gltf.animations.map((c) => [c.name, mixer.clipAction(c)]));
let current = actions.Idle;
current.play();
function transitionTo(name, duration = 0.3) {
const next = actions[name];
if (!next || next === current) return;
next.reset().play(); // Zurückspulen und alte Überblendung löschen
current.crossFadeTo(next, duration, false);
current = next;
}
4. Komprimierte Geometrie und Texturen
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader, DRACO_GLTF_CONFIG } 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 loader = new GLTFLoader()
.setDRACOLoader(new DRACOLoader().setDecoderPath(DRACO_GLTF_CONFIG)) // glTF-only WASM-Build (r185+)
.setKTX2Loader(new KTX2Loader().detectSupport(renderer)) // benötigt den Renderer
.setMeshoptDecoder(MeshoptDecoder);
// Diesen einen Loader für jedes Modell teilen, sodass Decoder und Worker nur einmal erstellt werden.
Bei Versionen vor r185 oder wenn der Host die gebündelten Dateien nicht ausliefert, die Ordner examples/jsm/libs/draco/ und libs/basis/ aus dem installierten three kopieren und diese Pfade an setDecoderPath / setTranscoderPath übergeben.
5. Ein benanntes Teil finden
const wheels = [];
gltf.scene.traverse((node) => {
if (node.name.startsWith('Wheel')) wheels.push(node);
});
// In der Schleife: for (const w of wheels) w.rotation.x += dt * 4;
6. Ein Modell verkleinern, ohne die vom Code benötigten Teile zu verlieren
# Meshopt-Komprimierung, WebP-Texturen maximal 1024 px, benannte Knoten und Hierarchie beibehalten.
npx @gltf-transform/cli optimize in.glb out.glb \
--compress meshopt --texture-compress webp --texture-size 1024 \
--flatten false --join-named false
npx @gltf-transform/cli validate out.glb
optimize flacht standardmäßig die Hierarchie ab und verbindet Meshes, einschließlich benannter. Das reduziert Draw Calls, aber Code, der Wheel_FL sucht oder einen Türknoten animiert, findet dann nichts. Die beiden Flags für jedes Modell beibehalten, in das der Code eingreift. Die Ausgabe benötigt setMeshoptDecoder (Muster 4).
Überprüfen
- Dateiprüfung:
npx @gltf-transform/cli validate model.glbfür jede neue oder geänderte Datei; gemeldete Fehler beheben, bevor Loader-Code debuggt wird. - Build:
npm run build(odernpx tsc --noEmit) läuft durch. - Laufzeitprobe:
sceneund den Mixer aufwindowverfügbar machen (Object.assign(window, { scene, mixer })). Diesen Ausdruck als String an Playwrightspage.evaluateübergeben, damit er in der Seite und nicht in Node ausgeführt wird (das Smoke-Skript inthreejs-scene-setupfunktioniert), oder den Benutzer bitten, ihn mitawaitdavor in die Browserkonsole einzufügen und die Ausgabe zu melden:
(async () => {
const before = window.mixer?.time ?? null;
await new Promise((r) => setTimeout(r, 500));
const meshes = [];
window.scene.traverse((o) => { if (o.isMesh) meshes.push(o.name || o.type); });
return { meshes: meshes.length, mixerAdvanced: before !== null && window.mixer.time > before };
})();
Eine Mesh-Anzahl ungleich null und mixerAdvanced: true erwarten, dann einen Screenshot auf Maßstab und Ausrichtung überprüfen.
Fallstricke
- Modell lädt, aber nichts wird angezeigt → PBR-Materialien ohne Licht oder Umgebung (siehe
threejs-materials-lighting), oder der Maßstab ist um den Faktor 100 falsch (ein Zentimeter-Export). Die Bounding Box aus Muster 1 protokollieren. gltfist außerhalb des Callbacks undefiniert →loadist asynchron.loadAsyncverwenden oder gemeinsame Referenzen innerhalb des Callbacks zuweisen.- Animation bewegt sich nie →
mixer.updatewird nicht jedes Bild aufgerufen, erhält Millisekunden oderplay()wurde nie aufgerufen. - 404 für
draco_*- oderbasis_*-Dateien oder ein Dekodierungsfehler → Die Decoder-Dateien werden nicht ausgeliefert oder stammen aus einer anderen three.js-Version. Die Kopien aus dem installiertenthreeausliefern und den Loader darauf verweisen. setKTX2Loader must be called before loading KTX2 texturesodersetMeshoptDecoder must be called before loading compressed files→ Die Datei verwendetKHR_texture_basisuoder Meshopt-Komprimierung; den Decoder anhängen (Muster 4)..hasFeature() called before the backend is initialized→KTX2Loader.detectSupportwurde auf einemWebGPURendererausgeführt, bevorawait renderer.init()abgeschlossen war.- Das gleiche Modell zweimal hinzufügen verschiebt es → Ein
Object3Dhat einen Elternteil. Klonen verwenden, und für geskinehte MeshesSkeletonUtils.clone(siehe Referenz). - Klone animieren gemeinsam oder nur einer bewegt sich → Ein einfaches
.clone()teilt sich das Skelett;SkeletonUtils.cloneund einen separaten Mixer pro Klon verwenden. - Benannte Teile verschwinden nach
gltf-transform optimize→ Die Standardeinstellungen zum Abflachen und Verbinden haben sie zusammengeführt. Mit--flatten false --join-named falseerneut ausführen. - Gebackene Offsets bekämpfen die Laufzeitsteuerung → Exporteure können Maßstab oder Rotation in Kindknoten einbrennen. Zuerst Namen und lokale Transformationen ausgeben; ein Teil unter einem frischen
Object3Dfür einen sauberen Drehpunkt neu anordnen oder einen Neuexport mit angewendeten Transformationen anfordern.
Referenzen
references/loaders-and-animation.mdlesen für eineLoadingManager-Fortschrittsanzeige für viele Loader, das Erzeugen vieler animierter Gegner mitSkeletonUtils.clone, Details zuAnimationAction-Schleifen und -Überblendungen, Hinweise zum Hosten von Decodern und Checklisten für den Export zur Weitergabe an einen Künstler.
Verwandte Fähigkeiten
threejs-scene-setup: Renderer, Kamera und Schleife.threejs-materials-lighting: Beleuchtung und Umgebung, damit PBR-Modelle richtig aussehen.create-game-assets: Briefing, Beschaffung und Prüfung der 3D-Assets selbst.fps-shooter: Ein 3D-Genre, das auf diesen Fähigkeiten aufbaut.
Versionshinweise
Zuletzt geprüft: 2026-11-11 gegen three r187 (npm [email protected], veröffentlicht 2026-10-30) und @gltf-transform/cli 4.5.1.
- r185:
DRACOLoaderundKTX2Loaderverwenden standardmäßig ihre gebündelten Decoder-Ordner;DRACO_GLTF_CONFIGhinzugefügt;DRACOLoader.setDecoderConfig()veraltet (Entfernung für r194 geplant). r183:KHR_meshopt_compressionwird zusätzlich zuEXT_meshopt_compressionunterstützt. r181:KTX2Loader.detectSupportAsync()veraltet. - gltf-transform 4.5.1
optimize-Standardeinstellungen:--compress meshopt,--flatten true,--join true,--join-named true,--simplify true,--texture-compress auto.--texture-compress ktx2benötigt denktx-Befehl aus KTX-Software 4.4.0 oder neuer imPATH. - Quellen: r187 Versionshinweise, r187 DRACOLoader.js, r187 GLTFLoader.js, glTF Transform CLI,
npx @gltf-transform/cli optimize --help.