Carga de glTF en three.js
Carga modelos .gltf / .glb, incluyendo geometría comprimida (DRACO, Meshopt) y texturas
(KTX2), y reproduce sus clips de animación. Los patrones están orientados a r187; un proyecto existente
mantiene su versión fija a menos que el usuario solicite una actualización. glTF es el formato de ejecución por defecto:
OBJ no tiene grafo de escena ni animación, y FBX es pesado de analizar en un navegador.
Cuándo usar
- Importar un modelo o personaje, inspeccionar su jerarquía de nodos, reproducir o mezclar clips, generar muchas copias de un enemigo animado, o corregir un modelo que no aparece.
- Los archivos son
.gltf/.glb, o el código importaGLTFLoader,DRACOLoaderoKTX2Loaderdesdethree/addons/loaders/.... - No aplica para el renderizador, cámara y bucle (
threejs-scene-setup), la iluminación y materiales del modelo (threejs-materials-lighting), ni para ajustes de modelado y exportación en una herramienta DCC.
Flujo de trabajo
- Inspecciona el archivo antes de escribir código de carga cuando
gltf-transformesté disponible:npx @gltf-transform/cli inspect model.glblista mallas, extensiones (por ejemploKHR_draco_mesh_compression,EXT_meshopt_compression,KHR_texture_basisu), clips y tamaños de textura. Cada extensión de compresión listada necesita su decodificador adjunto. - Carga con
GLTFLoader(loadAsyncen código asíncrono). El resultado tienegltf.scene, la raízObject3D, ygltf.animations, unAnimationClip[]. - Añade
gltf.sceney encuádralo. Las unidades de glTF son metros; registra nombres y límites para encontrar las partes que el código controlará. - Un
AnimationMixerpor raíz animada, acciones desdemixer.clipAction(clip), ymixer.update(segundos)en cada fotograma. - Adjunta decodificadores para las extensiones encontradas en el paso 1. Desde r185,
DRACOLoaderyKTX2Loaderencuentran sus archivos de decodificador incluidos sin necesidad de una ruta. - Verifica con Verificar.
Patrones
1. Cargar y encuadrar un modelo
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('tamaño (m):', box.getSize(new THREE.Vector3()).toArray());
console.log('clips:', gltf.animations.map((c) => c.name));
2. Reproducir un clip
const timer = new THREE.Timer(); // THREE.Clock está obsoleto desde 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()); // segundos, no milisegundos
renderer.render(scene, camera);
});
3. Transición suave entre 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(); // rebobina y limpia una transición anterior
current.crossFadeTo(next, duration, false);
current = next;
}
4. Geometría y texturas comprimidas
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)) // compilación WASM solo para glTF (r185+)
.setKTX2Loader(new KTX2Loader().detectSupport(renderer)) // necesita el renderizador
.setMeshoptDecoder(MeshoptDecoder);
// Comparte este único loader para todos los modelos para que los decodificadores y workers se creen una vez.
En versiones anteriores a r185, o cuando el servidor no sirve los archivos incluidos, copia
examples/jsm/libs/draco/ y libs/basis/ del paquete three instalado y pasa esas carpetas
a setDecoderPath / setTranscoderPath.
5. Encontrar una parte nombrada
const wheels = [];
gltf.scene.traverse((node) => {
if (node.name.startsWith('Wheel')) wheels.push(node);
});
// En el bucle: for (const w of wheels) w.rotation.x += dt * 4;
6. Reducir un modelo sin perder las partes que el código necesita
# Compresión Meshopt, texturas WebP de máximo 1024 px, conserva nodos nombrados y la jerarquía.
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 aplana la jerarquía y une mallas, incluidas las nombradas, por defecto. Eso
reduce las llamadas de dibujo, pero el código que busca Wheel_FL o anima un nodo de puerta entonces no
encuentra nada. Mantén las dos banderas anteriores para cualquier modelo al que el código acceda. La salida necesita
setMeshoptDecoder (Patrón 4).
Verificar
- Verificación de archivo:
npx @gltf-transform/cli validate model.glbpara cada archivo nuevo o modificado; corrige los errores reportados antes de depurar el código de carga. - Compilación:
npm run build(onpx tsc --noEmit) pasa. - Prueba en tiempo de ejecución: expón
sceney el mixer enwindow(Object.assign(window, { scene, mixer })). Pasa esta expresión apage.evaluatede Playwright como una cadena, para que se ejecute en la página y no en Node (el script de prueba rápida enthreejs-scene-setupfunciona), o pide al usuario que la pegue en la consola del navegador conawaital inicio y que reporte la salida:
(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 };
})();
Espera un conteo de mallas distinto de cero y mixerAdvanced: true, luego verifica una captura de pantalla para
la escala y orientación.
Problemas comunes
- El modelo se carga pero no se muestra → Materiales PBR sin luz ni entorno (consulta
threejs-materials-lighting), o la escala está desviada por 100 (exportación en centímetros). Registra la caja delimitadora del Patrón 1. gltfno está definido fuera del callback →loades asíncrono. UsaloadAsync, o asigna referencias compartidas dentro del callback.- La animación nunca se mueve →
mixer.updateno se llama en cada fotograma, se le pasan milisegundos, o nunca se llamó aplay(). - Error 404 para archivos
draco_*obasis_*, o un error de decodificación → los archivos del decodificador no se sirven, o provienen de otra versión de three.js. Sirve las copias desde el paquetethreeinstalado y apunta el loader hacia ellas. setKTX2Loader must be called before loading KTX2 texturesosetMeshoptDecoder must be called before loading compressed files→ el archivo usaKHR_texture_basisuo compresión meshopt; adjunta el decodificador (Patrón 4)..hasFeature() called before the backend is initialized→KTX2Loader.detectSupportse ejecutó en unWebGPURendererantes de queawait renderer.init()terminara.- Agregar el mismo modelo dos veces lo mueve → un
Object3Dtiene un solo padre. Clónalo, y usaSkeletonUtils.clonepara mallas con esqueleto (consulta la referencia). - Los clones se animan juntos, o solo uno se mueve → un
.clone()simple comparte el esqueleto; usaSkeletonUtils.cloney un mixer separado por cada clon. - Las partes nombradas desaparecen después de
gltf-transform optimize→ el aplanamiento y unión por defecto las fusionaron. Vuelve a ejecutar con--flatten false --join-named false. - Los offsets incorporados entran en conflicto con el control en tiempo de ejecución → los exportadores pueden
incorporar escala o rotación en nodos hijos. Primero vuelca nombres y transformaciones locales; re-parenta una parte
bajo un nuevo
Object3Dpara un pivote limpio, o pide una reexportación con transformaciones aplicadas.
Referencias
- Lee
references/loaders-and-animation.mdpara una barra de progreso conLoadingManagera través de múltiples loaders, generación de muchos enemigos animados conSkeletonUtils.clone, detalles de bucle y mezcla deAnimationAction, notas sobre alojamiento de decodificadores, y listas de verificación para exportadores que puedas entregar a un artista.
Habilidades relacionadas
threejs-scene-setup: renderizador, cámara y bucle.threejs-materials-lighting: iluminación y entorno para que los modelos PBR luzcan correctamente.create-game-assets: briefing, obtención y verificación de los propios activos 3D.fps-shooter: un género 3D que se basa en estas habilidades.
Notas de versión
Última verificación: 2026-11-11 contra three r187 (npm [email protected], publicado 2026-10-30) y
@gltf-transform/cli 4.5.1.
- r185:
DRACOLoaderyKTX2Loaderusan por defecto sus carpetas de decodificador incluidas; se añadióDRACO_GLTF_CONFIG;DRACOLoader.setDecoderConfig()obsoleto (eliminación prevista para r194). r183: Se soportaKHR_meshopt_compressionjunto conEXT_meshopt_compression. r181:KTX2Loader.detectSupportAsync()obsoleto. - gltf-transform 4.5.1 valores por defecto de
optimize:--compress meshopt,--flatten true,--join true,--join-named true,--simplify true,--texture-compress auto.--texture-compress ktx2necesita el comandoktxde KTX-Software 4.4.0 o más reciente enPATH. - Fuentes: Notas de la versión r187,
r187 DRACOLoader.js,
r187 GLTFLoader.js,
CLI de glTF Transform,
npx @gltf-transform/cli optimize --help.