Carregamento glTF no three.js
Carrega modelos .gltf / .glb, incluindo geometria comprimida (DRACO, Meshopt) e texturas
(KTX2), e reproduz seus clipes de animação. Os padrões são direcionados à r187; um projeto existente
mantém sua versão fixa, a menos que o usuário solicite uma atualização. glTF é o formato padrão de tempo de execução:
OBJ não tem grafo de cena nem animação, e FBX é pesado de analisar em um navegador.
Quando usar
- Importar um modelo ou personagem, inspecionar sua hierarquia de nós, reproduzir ou fazer transição entre clipes, gerar várias cópias de um inimigo animado, ou corrigir um modelo que não aparece.
- Os arquivos são
.gltf/.glb, ou o código importaGLTFLoader,DRACOLoaderouKTX2Loaderdethree/addons/loaders/.... - Não é para o renderizador, câmera e loop (
threejs-scene-setup), iluminação e materiais do modelo (threejs-materials-lighting), ou configurações de modelagem e exportação em uma ferramenta DCC.
Fluxo de trabalho
- Inspecione o arquivo antes de escrever o código do carregador quando
gltf-transformestiver disponível:npx @gltf-transform/cli inspect model.glblista malhas, extensões (por exemploKHR_draco_mesh_compression,EXT_meshopt_compression,KHR_texture_basisu), clipes e tamanhos de textura. Cada extensão de compressão listada precisa que seu decodificador seja anexado. - Carregue com
GLTFLoader(loadAsyncem código assíncrono). O resultado temgltf.scene, a raizObject3D, egltf.animations, umAnimationClip[]. - Adicione
gltf.scenee enquadre-o. Unidades glTF são metros; registre nomes e limites para encontrar as partes que o código irá controlar. - Um
AnimationMixerpor raiz animada, ações a partir demixer.clipAction(clip), emixer.update(segundos)a cada quadro. - Anexe decodificadores para as extensões encontradas no passo 1. Desde a r185,
DRACOLoadereKTX2Loaderencontram seus arquivos de decodificação incluídos sem a necessidade de um caminho. - Verifique com Verificar.
Padrões
1. Carregar e enquadrar um 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('tamanho (m):', box.getSize(new THREE.Vector3()).toArray());
console.log('clipes:', gltf.animations.map((c) => c.name));
2. Reproduzir um clipe
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, não milissegundos
renderer.render(scene, camera);
});
3. Transição suave entre clipes
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 e limpa uma transição antiga
current.crossFadeTo(next, duration, false);
current = next;
}
4. Geometria e 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)) // compilação WASM apenas para glTF (r185+)
.setKTX2Loader(new KTX2Loader().detectSupport(renderer)) // precisa do renderizador
.setMeshoptDecoder(MeshoptDecoder);
// Compartilhe este único carregador para todos os modelos para que decodificadores e workers sejam criados uma vez.
Em versões anteriores à r185, ou quando o host não serve os arquivos incluídos, copie
examples/jsm/libs/draco/ e libs/basis/ do three instalado e passe essas pastas
para setDecoderPath / setTranscoderPath.
5. Encontrar uma parte nomeada
const wheels = [];
gltf.scene.traverse((node) => {
if (node.name.startsWith('Wheel')) wheels.push(node);
});
// No loop: for (const w of wheels) w.rotation.x += dt * 4;
6. Reduzir um modelo sem perder as partes que o código precisa
# Compressão Meshopt, texturas WebP com no máximo 1024 px, manter nós nomeados e a hierarquia.
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 achata a hierarquia e une malhas, incluindo as nomeadas, por padrão. Isso
reduz chamadas de desenho, mas o código que procura por Wheel_FL ou anima um nó de porta então não
encontra nada. Mantenha as duas flags acima para qualquer modelo que o código acesse. A saída precisa
de setMeshoptDecoder (Padrão 4).
Verificar
- Verificação do arquivo:
npx @gltf-transform/cli validate model.glbpara cada arquivo novo ou alterado; corrija os erros relatados antes de depurar o código do carregador. - Compilação:
npm run build(ounpx tsc --noEmit) passa. - Sonda em tempo de execução: exponha
scenee o mixer emwindow(Object.assign(window, { scene, mixer })). Passe esta expressão parapage.evaluatedo Playwright como uma string, para que ela seja executada na página e não no Node (o script de teste emthreejs-scene-setupfunciona), ou peça ao usuário para colá-la no console do navegador comawaitna frente e relatar a saída:
(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 };
})();
Espere uma contagem de malhas diferente de zero e mixerAdvanced: true, depois verifique uma captura de tela
para escala e orientação.
Armadilhas
- Modelo carrega mas nada aparece → Materiais PBR sem luz ou ambiente (veja
threejs-materials-lighting), ou a escala está errada por 100 (exportação em centímetros). Registre a caixa delimitadora do Padrão 1. gltfé indefinido fora do callback →loadé assíncrono. UseloadAsync, ou atribua referências compartilhadas dentro do callback.- Animação nunca se move →
mixer.updatenão é chamado a cada quadro, recebe milissegundos, ouplay()nunca foi chamado. - Erro 404 para arquivos
draco_*oubasis_*, ou um erro de decodificação → os arquivos do decodificador não estão sendo servidos, ou vêm de outra versão do three.js. Sirva as cópias dothreeinstalado e aponte o carregador para elas. setKTX2Loader deve ser chamado antes de carregar texturas KTX2ousetMeshoptDecoder deve ser chamado antes de carregar arquivos comprimidos→ o arquivo usaKHR_texture_basisuou compressão meshopt; anexe o decodificador (Padrão 4)..hasFeature() foi chamado antes do backend ser inicializado→KTX2Loader.detectSupportfoi executado em umWebGPURendererantes deawait renderer.init()terminar.- Adicionar o mesmo modelo duas vezes o move → um
Object3Dtem um único pai. Clone-o e useSkeletonUtils.clonepara malhas com skin (veja a referência). - Clones animam juntos, ou apenas um se move → uma
.clone()simples compartilha o esqueleto; useSkeletonUtils.clonee um mixer separado para cada clone. - Partes nomeadas desaparecem após
gltf-transform optimize→ o achatamento e junção padrão as mesclaram. Execute novamente com--flatten false --join-named false. - Deslocamentos enrijecidos competem com o controle em tempo de execução → exportadores podem enrijecer escala ou rotação em nós
filhos. Primeiro, despeje nomes e transformações locais; re-parente uma parte sob um novo
Object3Dpara um pivô limpo, ou peça uma reexportação com transformações aplicadas.
Referências
- Leia
references/loaders-and-animation.mdpara uma barra de progresso doLoadingManagerentre vários carregadores, gerando muitos inimigos animados comSkeletonUtils.clone, detalhes de looping e mesclagem doAnimationAction, notas sobre hospedagem de decodificadores e listas de verificação para exportadores para entregar a um artista.
Habilidades relacionadas
threejs-scene-setup: renderizador, câmera e loop.threejs-materials-lighting: iluminação e ambiente para que modelos PBR pareçam corretos.create-game-assets: briefing, obtenção e verificação dos próprios ativos 3D.fps-shooter: um gênero 3D que se baseia nestas habilidades.
Notas de versão
Última verificação: 2026-11-11 contra three r187 (npm [email protected], publicado em 2026-10-30) e
@gltf-transform/cli 4.5.1.
- r185:
DRACOLoadereKTX2Loaderusam por padrão suas pastas de decodificação incluídas;DRACO_GLTF_CONFIGadicionado;DRACOLoader.setDecoderConfig()obsoleto (remoção planejada para r194). r183: suporte aKHR_meshopt_compressionao lado deEXT_meshopt_compression. r181:KTX2Loader.detectSupportAsync()obsoleto. - Otimização
optimizedo gltf-transform 4.5.1: valores padrão:--compress meshopt,--flatten true,--join true,--join-named true,--simplify true,--texture-compress auto.--texture-compress ktx2precisa do comandoktxdo KTX-Software 4.4.0 ou mais recente noPATH. - Fontes: Notas de lançamento da r187,
r187 DRACOLoader.js,
r187 GLTFLoader.js,
CLI glTF Transform,
npx @gltf-transform/cli optimize --help.