Que fait GLB dans three.js ?
Charge des modèles .gltf / .glb, y compris avec géométrie compressée (DRACO, Meshopt) et textures
(KTX2), et joue leurs clips d'animation. Les patrons ciblent r187 ; un projet existant conserve
sa version épinglée sauf si l'utilisateur demande une mise à niveau. glTF est le format d'exécution par défaut :
OBJ n'a ni graphe de scène ni animation, et FBX est lourd à analyser dans un navigateur.
Quand l'utiliser
- Importer un modèle ou un personnage, inspecter sa hiérarchie de nœuds, jouer ou fondre des clips, générer de nombreuses copies d'un ennemi animé, ou corriger un modèle qui n'apparaît pas.
- Les fichiers sont
.gltf/.glb, ou le code importeGLTFLoader,DRACOLoaderouKTX2Loaderdepuisthree/addons/loaders/.... - Ne concerne pas le rendu, la caméra et la boucle (
threejs-scene-setup), l'éclairage et les matériaux du modèle (threejs-materials-lighting), ni les paramètres de modélisation et d'exportation dans un outil DCC.
Flux de travail
- Inspecter le fichier avant d'écrire le code de chargement lorsque
gltf-transformest disponible :npx @gltf-transform/cli inspect model.glbliste les maillages, extensions (par exempleKHR_draco_mesh_compression,EXT_meshopt_compression,KHR_texture_basisu), clips et tailles de texture. Chaque extension de compression listée nécessite que son décodeur soit attaché. - Charger avec
GLTFLoader(loadAsyncen code asynchrone). Le résultat agltf.scene, leObject3Dracine, etgltf.animations, unAnimationClip[]. - Ajouter
gltf.sceneet le cadrer. Les unités glTF sont en mètres ; enregistrer les noms et les limites pour trouver les parties que le code contrôlera. - Un
AnimationMixerpar racine animée, actions viamixer.clipAction(clip), etmixer.update(secondes)à chaque image. - Attacher les décodeurs pour les extensions trouvées à l'étape 1. Depuis r185,
DRACOLoaderetKTX2Loadertrouvent leurs fichiers décodeurs intégrés sans chemin. - Vérifier avec Vérification.
Patrons
1. Charger et cadrer un modèle
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('taille (m) :', box.getSize(new THREE.Vector3()).toArray());
console.log('clips :', gltf.animations.map((c) => c.name));
2. Jouer un clip
const timer = new THREE.Timer(); // THREE.Clock est déprécié depuis r183
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()); // secondes, pas millisecondes
renderer.render(scene, camera);
});
3. Fondu enchaîné entre des clips
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(); // rembobiner et effacer un ancien fondu
current.crossFadeTo(next, duration, false);
current = next;
}
4. Géométrie et textures compressées
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)) // build WASM glTF uniquement (r185+)
.setKTX2Loader(new KTX2Loader().detectSupport(renderer)) // nécessite le rendu
.setMeshoptDecoder(MeshoptDecoder);
// Partager ce seul chargeur pour chaque modèle afin que les décodeurs et workers soient créés une fois.
Sur les versions antérieures à r185, ou lorsque l'hôte ne sert pas les fichiers intégrés, copier
examples/jsm/libs/draco/ et libs/basis/ depuis le dossier three installé et passer ces dossiers
à setDecoderPath / setTranscoderPath.
5. Trouver une partie nommée
const wheels = [];
gltf.scene.traverse((node) => {
if (node.name.startsWith('Wheel')) wheels.push(node);
});
// Dans la boucle : for (const w of wheels) w.rotation.x += dt * 4;
6. Réduire un modèle sans perdre les parties dont le code a besoin
# Compression Meshopt, textures WebP de 1024 px max, conserver les nœuds nommés et la hiérarchie.
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 aplatit la hiérarchie et fusionne les maillages, y compris les nommés, par défaut. Cela
réduit les appels de dessin, mais le code qui cherche Wheel_FL ou anime un nœud de porte ne trouve alors
rien. Conserver les deux indicateurs ci-dessus pour tout modèle que le code manipule. La sortie nécessite
setMeshoptDecoder (Patron 4).
Vérification
- Vérification du fichier :
npx @gltf-transform/cli validate model.glbpour chaque fichier nouveau ou modifié ; corriger les erreurs signalées avant de déboguer le code de chargement. - Build :
npm run build(ounpx tsc --noEmit) passe. - Son de runtime : exposer
sceneet le mixer surwindow(Object.assign(window, { scene, mixer })). Passer cette expression àpage.evaluatede Playwright sous forme de chaîne, pour qu'elle s'exécute dans la page et non dans Node (le script de test dansthreejs-scene-setupfonctionne), ou demander à l'utilisateur de la coller dans la console du navigateur avecawaitdevant et de rapporter la sortie :
(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 };
})();
Attendre un nombre de maillages non nul et mixerAdvanced: true, puis vérifier une capture d'écran pour
l'échelle et l'orientation.
Pièges
- Le modèle se charge mais rien ne s'affiche → Matériaux PBR sans lumière ni environnement (voir
threejs-materials-lighting), ou l'échelle est erronée d'un facteur 100 (export en centimètres). Enregistrer la boîte englobante du Patron 1. gltfest indéfini en dehors du callback →loadest asynchrone. UtiliserloadAsync, ou assigner des références partagées à l'intérieur du callback.- L'animation ne bouge jamais →
mixer.updaten'est pas appelé à chaque image, on lui donne des millisecondes, ouplay()n'a jamais été appelé. - Erreur 404 pour les fichiers
draco_*oubasis_*, ou une erreur de décodage → les fichiers décodeurs ne sont pas servis, ou proviennent d'une autre version de three.js. Servir les copies depuis le dossierthreeinstallé et pointer le chargeur vers elles. setKTX2Loader must be called before loading KTX2 texturesousetMeshoptDecoder must be called before loading compressed files→ le fichier utiliseKHR_texture_basisuou la compression meshopt ; attacher le décodeur (Patron 4)..hasFeature() called before the backend is initialized→KTX2Loader.detectSupporta été exécuté sur unWebGPURendereravant la fin deawait renderer.init().- Ajouter le même modèle deux fois le déplace → un
Object3Da un seul parent. Le cloner, et utiliserSkeletonUtils.clonepour les maillages skin (voir la référence). - Les clones s'animent ensemble, ou un seul bouge → un
.clone()simple partage le squelette ; utiliserSkeletonUtils.cloneet un mixer séparé par clone. - Les parties nommées disparaissent après
gltf-transform optimize→ l'aplatissement et la fusion par défaut les ont fusionnées. Relancer avec--flatten false --join-named false. - Les décalages cuits au four entrent en conflit avec le contrôle runtime → les exportateurs peuvent cuire l'échelle ou la rotation
dans les nœuds enfants. Vider d'abord les noms et les transformations locales ; reassigner une partie sous un nouveau
Object3Dpour un pivot propre, ou demander une ré-exportation avec transformations appliquées.
Références
- Lire
references/loaders-and-animation.mdpour une barre de progressionLoadingManagerpour plusieurs chargeurs, générer de nombreux ennemis animés avecSkeletonUtils.clone, les détails de bouclage et de mélangeAnimationAction, les notes d'hébergement de décodeur, et une liste de contrôle pour l'exportateur à remettre à un artiste.
Compétences connexes
threejs-scene-setup: rendu, caméra et boucle.threejs-materials-lighting: éclairage et environnement pour que les modèles PBR aient un bon aspect.create-game-assets: briefing, recherche et vérification des actifs 3D eux-mêmes.fps-shooter: un genre 3D qui s'appuie sur ces compétences.
Notes de version
Dernière vérification : 2026-11-11 avec three r187 (npm [email protected], publié le 2026-10-30) et
@gltf-transform/cli 4.5.1.
- r185 :
DRACOLoaderetKTX2Loaderse réfèrent par défaut à leurs dossiers de décodeurs intégrés ;DRACO_GLTF_CONFIGajouté ;DRACOLoader.setDecoderConfig()déprécié (suppression prévue pour r194). r183 :KHR_meshopt_compressionsupporté en plus deEXT_meshopt_compression. r181 :KTX2Loader.detectSupportAsync()déprécié. - Paramètres par défaut de
gltf-transform4.5.1optimize:--compress meshopt,--flatten true,--join true,--join-named true,--simplify true,--texture-compress auto.--texture-compress ktx2nécessite la commandektxde KTX-Software 4.4.0 ou plus récent sur la variable d'environnementPATH. - Sources : Notes de version r187,
r187 DRACOLoader.js,
r187 GLTFLoader.js,
CLI glTF Transform,
npx @gltf-transform/cli optimize --help.