¿Qué hace Pipeline Web de Three.js y glTF?
Este skill cubre los pasos para convertir un modelo de Blender o vcad en un archivo .glb pequeño. El archivo debe cargar rápido y animarse fácilmente en Three.js.
1. Lista de verificación de exportación para Blender y vcad
Nombres de nodos
- Nombra cada parte móvil con un nombre claro y estable:
Head,Visor,Eye_L,Eye_R,Torso_Door,Wheel_FL,Wheel_FR,Steering_Wheel. - Luego Three.js encuentra la parte con
model.getObjectByName("Torso_Door").
Pivotes
- Coloca el origen raíz en el centro de la base del modelo. En Three.js, el modelo se asienta en el suelo en
Y = 0. - Coloca el pivote de cada parte articulada en su eje de rotación. Ejemplos: bisagra de puerta, centro de rueda, base de cuello, base de antena.
Transformaciones
- Aplica todas las transformaciones antes de exportar.
- La escala debe ser
1, 1, 1. La rotación de reposo debe ser0, 0, 0. - Esta regla evita desviaciones y deformaciones durante la animación procedural.
Presupuesto de geometría
- Une mallas estáticas que compartan un material. Este paso reduce las llamadas de dibujo.
- Mantén una malla separada solo si un script la anima por sí sola. Usa un
SkinnedMeshcon un armazón para deformación suave. - Apunta a unos pocos miles de triángulos por activo principal. Apunta a menos de 1,000 triángulos para elementos de fondo.
2. Optimización CLI con @gltf-transform/cli
El proyecto usa Bun. Ejecuta la herramienta con bunx. npx también funciona en máquinas que tengan Node.js.
# Muestra mallas, texturas y animaciones
bunx @gltf-transform/cli inspect model.glb
# Optimización completa para la web: Meshopt más WebP más limpieza
bunx @gltf-transform/cli optimize model.glb model-optimized.glb \
--compress meshopt \
--texture-compress webp \
--texture-size 2048
# Alternativa: Compresión de geometría Draco
bunx @gltf-transform/cli draco model.glb model-draco.glb
Meshopt o Draco
- Meshopt (
EXT_meshopt_compression) decodifica muy rápido. Mantiene el orden de los vértices y también comprime fotogramas clave de animación y objetivos de morfología. Úsalo para activos animados. - Draco (
KHR_draco_mesh_compression) da el archivo más pequeño para mallas estáticas densas. Ejemplos: carrocerías y escaneos. El decodificador cuesta más tiempo al inicio.
Otros pasos útiles
# Elimina mallas duplicadas y datos no utilizados
bunx @gltf-transform/cli dedup model.glb model.glb
# Convierte texturas a KTX2 (BasisU)
bunx @gltf-transform/cli etc1s model.glb model-ktx2.glb
Revisa el archivo después de cada paso. Confirma el tamaño del archivo, el conteo de triángulos y el tamaño de las texturas.
3. Integración con Three.js
Cargador robusto con Draco y Meshopt
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
import { MeshoptDecoder } from 'three/addons/libs/meshopt_decoder.module.js';
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('https://www.gstatic.com/draco/versioned/decoders/1.5.7/');
const gltfLoader = new GLTFLoader();
gltfLoader.setDRACOLoader(dracoLoader);
gltfLoader.setMeshoptDecoder(MeshoptDecoder);
const gltf = await gltfLoader.loadAsync('/models/bender-optimized.glb');
const root = gltf.scene;
scene.add(root);
Dos métodos de animación
- Animación procedural con transformaciones de nodos. Usa este método para robots, vehículos y otras partes rígidas. Ejemplos: giro de rueda, apertura de puerta, seguimiento de cabeza, balanceo de antena.
const head = root.getObjectByName('Head');
const door = root.getObjectByName('Torso_Door');
const antenna = root.getObjectByName('Antenna');
function animate(time) {
if (antenna) {
antenna.rotation.z = Math.sin(time * 0.005) * 0.15;
}
if (head) {
head.rotation.y = THREE.MathUtils.lerp(head.rotation.y, targetYaw, 0.1);
}
}
- Clips horneados con
THREE.AnimationMixer. Usa este método para ciclos complejos que vienen de Blender: caminar, bailar y morfologías faciales.
const mixer = new THREE.AnimationMixer(root);
const idleClip = THREE.AnimationClip.findByName(gltf.animations, 'Idle');
if (idleClip) {
mixer.clipAction(idleClip).play();
}
// En el bucle de renderizado:
// mixer.update(clock.getDelta());
Iluminación PBR para piezas metálicas
Un material metálico (metalness > 0.8) se ve negro en Three.js cuando no hay nada que lo refleje. Configura un mapa de entorno:
import { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js';
const pmremGenerator = new THREE.PMREMGenerator(renderer);
scene.environment = pmremGenerator.fromScene(new RoomEnvironment(), 0.04).texture;
Usa scene.environmentIntensity para ajustar la intensidad del reflejo. Mantén el mapeo de tono en THREE.ACESFilmicToneMapping para activos metálicos.
Reglas de rendimiento
- Un material por grupo de malla. Cada material cuesta una llamada de dibujo.
- Reutiliza texturas. Empaqueta texturas pequeñas en un solo atlas.
- Configura
renderer.outputColorSpace = THREE.SRGBColorSpace. El cargador glTF establece los espacios de color de las texturas. - Usa
THREE.InstancedMeshcuando un activo aparece muchas veces. - Libera un modelo cuando lo elimines: recorre la escena, luego llama a
geometry.dispose()ymaterial.dispose().