O que Three.js e Pipeline Web glTF faz?
Este skill cobre as etapas que transformam um modelo do Blender ou vcad em um arquivo .glb pequeno. O arquivo deve carregar rápido e animar facilmente no Three.js.
1. Checklist de exportação para Blender e vcad
Nomes dos nós
- Nomeie cada parte móvel com um nome claro e estável:
Head,Visor,Eye_L,Eye_R,Torso_Door,Wheel_FL,Wheel_FR,Steering_Wheel. - O Three.js então encontra a parte com
model.getObjectByName("Torso_Door").
Pivôs
- Coloque a origem raiz no centro da base do modelo. No Three.js, o modelo então fica no chão em
Y = 0. - Coloque cada pivô de parte articulada em seu eixo de rotação. Exemplos: dobradiça da porta, centro da roda, base do pescoço, base da antena.
Transformações
- Aplique todas as transformações antes da exportação.
- A escala deve ser
1, 1, 1. A rotação de repouso deve ser0, 0, 0. - Esta regra evita deriva e cisalhamento durante a animação procedural.
Orçamento de geometria
- Junte as malhas estáticas que compartilham um material. Este passo reduz as chamadas de draw.
- Mantenha uma malha separada apenas se um script a animar sozinha. Use um
SkinnedMeshcom um armature para deformação suave. - Almeje alguns milhares de triângulos por asset principal. Almeje abaixo de 1.000 triângulos para objetos de fundo.
2. Otimização via CLI com @gltf-transform/cli
O projeto usa Bun. Execute a ferramenta com bunx. npx também funciona em máquinas que têm Node.js.
# Mostrar malhas, texturas e animações
bunx @gltf-transform/cli inspect model.glb
# Otimização completa para a web: Meshopt mais WebP mais limpeza
bunx @gltf-transform/cli optimize model.glb model-optimized.glb \
--compress meshopt \
--texture-compress webp \
--texture-size 2048
# Alternativa: Compressão de geometria Draco
bunx @gltf-transform/cli draco model.glb model-draco.glb
Meshopt ou Draco
- Meshopt (
EXT_meshopt_compression) decodifica muito rápido. Ele mantém a ordem dos vértices e também comprime keyframes de animação e alvos de morph. Use-o para assets animados. - Draco (
KHR_draco_mesh_compression) gera o menor arquivo para malhas estáticas densas. Exemplos: carrocerias e digitalizações. O decodificador custa mais tempo na inicialização.
Outros passos úteis
# Remover malhas duplicadas e dados não utilizados
bunx @gltf-transform/cli dedup model.glb model.glb
# Converter texturas para KTX2 (BasisU)
bunx @gltf-transform/cli etc1s model.glb model-ktx2.glb
Verifique o arquivo após cada passo. Confirme o tamanho do arquivo, a contagem de triângulos e o tamanho das texturas.
3. Integração com Three.js
Carregador robusto com Draco e 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);
Dois métodos de animação
- Animação procedural com transformações de nó. Use este método para robôs, veículos e outras partes rígidas. Exemplos: rotação de roda, abertura de porta, rastreamento de cabeça, balanço 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);
}
}
- Clipes processados com
THREE.AnimationMixer. Use este método para ciclos complexos vindos do Blender: caminhada, dança e morphs faciais.
const mixer = new THREE.AnimationMixer(root);
const idleClip = THREE.AnimationClip.findByName(gltf.animations, 'Idle');
if (idleClip) {
mixer.clipAction(idleClip).play();
}
// No loop de renderização:
// mixer.update(clock.getDelta());
Iluminação PBR para peças metálicas
Um material metálico (metalness > 0.8) fica preto no Three.js quando nada o rodeia. Defina um mapa de ambiente:
import { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js';
const pmremGenerator = new THREE.PMREMGenerator(renderer);
scene.environment = pmremGenerator.fromScene(new RoomEnvironment(), 0.04).texture;
Use scene.environmentIntensity para ajustar a força do reflexo. Mantenha o mapeamento de tom em THREE.ACESFilmicToneMapping para assets metálicos.
Regras de performance
- Um material por grupo de malha. Cada material custa uma chamada de draw.
- Reutilize texturas. Empacote texturas pequenas em um atlas.
- Defina
renderer.outputColorSpace = THREE.SRGBColorSpace. O carregador glTF define os espaços de cor das texturas. - Use
THREE.InstancedMeshquando um asset aparece muitas vezes. - Libere um modelo ao removê-lo: percorra a cena, depois chame
geometry.dispose()ematerial.dispose().