O que é 3D na web?
O WebGL permite que o navegador renderize 3D com aceleração de hardware utilizando a GPU. Ele é poderoso, mas a API bruta é verbosa: você precisa gerenciar buffers, escrever shaders e lidar com a matemática por conta própria. O Three.js encapsula o WebGL em um scene graph amigável, permitindo que você descreva objetos, luzes e câmeras enquanto a biblioteca cuida do restante.
O resultado é que o 3D na web tornou-se prático para configuradores de produtos, visualização de dados, storytelling interativo, jogos e experiências imersivas em WebXR. Não é a escolha certa para todo site, mas quando o movimento e o espaço contam a história melhor do que uma página plana, o Three.js é a ferramenta padrão.
Cena, câmera e renderer
Todo app Three.js possui três objetos principais.
// setup.js
import * as THREE from "three";
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, innerWidth / innerHeight, 0.1, 100);
camera.position.set(0, 0, 3);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
A scene é o container. A camera define a visualização; PerspectiveCamera proporciona profundidade realista, enquanto OrthographicCamera é útil para visualizações planas ou isométricas. O renderer desenha a cena em um canvas. Limitar o pixel ratio evita que telas de alta densidade renderizem mais pixels do que o necessário.
Meshes, geometria e materiais
Um objeto visível é um mesh: uma geometria para a sua forma e um material para a sua superfície.
// mesh.js
const cube = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshStandardMaterial({ color: 0x22c55e, roughness: 0.4 }),
);
cube.position.set(0, 0, 0);
scene.add(cube);
O Three.js já vem com diversas geometrias integradas (box, sphere, plane, torus e outras) e materiais para diferentes visuais. MeshStandardMaterial responde a luzes e é uma boa opção padrão; MeshBasicMaterial ignora a iluminação e é mais leve. Meshes podem ser agrupados e aninhados, formando o scene graph através do qual as transformações são herdadas.
Luzes e sombras
Sem luz, a maioria dos materiais é renderizada em preto.
// lights.js
const ambient = new THREE.AmbientLight(0xffffff, 0.4);
const key = new THREE.DirectionalLight(0xffffff, 2.5);
key.position.set(2, 3, 2);
scene.add(ambient, key);
As luzes são objetos na cena, portanto, sua posição e tipo são importantes. As sombras exigem a ativação de renderer.shadowMap e a marcação da luz, do objeto e da superfície; elas são relativamente custosas, então use-as com critério. Cada luz adiciona custo ao processamento, portanto, mantenha a quantidade baixa.
Modelos e texturas
Projetos reais geralmente carregam assets em vez de construir a geometria manualmente. O glTF é o formato 3D padrão para a web.
// load.js
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
const loader = new GLTFLoader();
loader.load("/models/robot.glb", (gltf) => {
scene.add(gltf.scene);
});
As texturas são carregadas de forma semelhante com TextureLoader, e RGBELoader ou PMREMGenerator podem fornecer mapas de ambiente para reflexos realistas. Mantenha o tamanho dos modelos e das texturas razoável, já que eles dominam o tempo de carregamento e o uso de memória.
O loop de animação
A animação atualiza a cena e a renderiza novamente a cada frame.
// loop.js
const clock = new THREE.Clock();
renderer.setAnimationLoop(() => {
const delta = clock.getDelta();
cube.rotation.y += delta;
renderer.render(scene, camera);
});
Usar delta mantém a velocidade do movimento consistente, independentemente da taxa de quadros (frame rate). Quando a cena estiver estática, renderize sob demanda em vez de continuamente: renderize após uma alteração, uma interação de controle ou uma animação, e pare quando nada estiver acontecendo. Isso economiza bateria e GPU em dispositivos móveis.
Interação
Para tornar objetos clicáveis ou interativos ao passar o mouse (hover), utilize um Raycaster.
// pick.js
const raycaster = new THREE.Raycaster();
const pointer = new THREE.Vector2();
addEventListener("pointerdown", (event) => {
pointer.x = (event.clientX / innerWidth) * 2 - 1;
pointer.y = -(event.clientY / innerHeight) * 2 + 1;
raycaster.setFromCamera(pointer, camera);
const hit = raycaster.intersectObjects(scene.children)[0];
if (hit) hit.object.material.color.set(0xf97316);
});
O Raycasting a partir da câmera através do ponteiro retorna os objetos sob ele, o que é suficiente para seleção, destaque e interações simples.
Performance e limpeza
O 3D é a coisa mais cara que a maioria dos sites irá renderizar, por isso a disciplina é fundamental.
- Descarte (Dispose) geometrias, materiais e texturas ao remover objetos; eles residem na memória da GPU.
- Reutilize geometrias e materiais entre instâncias em vez de criar novos.
- Mescle (Merge) geometrias estáticas e utilize instanciamento para objetos repetidos.
- Limite as luzes e os objetos que projetam sombras.
- Reduza o pixel ratio em telas de alta densidade.
- Renderize sob demanda para cenas estáticas.
- Pause a renderização quando o canvas estiver fora da tela.
// dispose.js
mesh.geometry.dispose();
mesh.material.dispose();
scene.remove(mesh);
Esquecer de fazer o dispose é a causa mais comum de apps Three.js que consomem lentamente toda a memória disponível.
React Three Fiber
Com React, o React Three Fiber renderiza Three.js de forma declarativa, permitindo que a cena seja descrita com componentes e se integre ao estado e ciclo de vida do React.
// Scene.jsx
import { Canvas } from "@react-three/fiber";
import { OrbitControls } from "@react-three/drei";
export function Scene() {
return (
<Canvas>
<ambientLight intensity={0.4} />
<directionalLight position={[2, 3, 2]} intensity={2.5} />
<mesh>
<boxGeometry />
<meshStandardMaterial color="#22c55e" />
</mesh>
<OrbitControls />
</Canvas>
);
}
Os helpers do drei fornecem controles, ambientes e abstrações comuns. Esta é a maneira recomendada de utilizar Three.js no React.
Melhores práticas
- Limite o pixel ratio e redimensione o renderer conforme a janela.
- Reutilize geometry e materials; utilize instanciamento para objetos repetidos.
- Libere os recursos da GPU ao remover objetos.
- Mantenha o número de luzes e shadow casters no mínimo possível.
- Renderize sob demanda para cenas estáticas.
- Teste em dispositivos móveis reais de gama média.
- Forneça um fallback para quando o WebGL não estiver disponível.
Erros comuns
- Esquecer de fazer o dispose e causar vazamento de memória da GPU.
- Renderizar continuamente quando nada muda.
- Criar novas geometrias ou materiais a cada frame.
- Adicionar muitas luzes e sombras sem realizar medições.
- Carregar modelos e texturas enormes e não otimizados.
- Testar apenas em um desktop rápido e publicar para mobile.
Próximos passos
O Three.js abre toda uma nova dimensão para a web. Adicione movimentos coreografados com o guia de Animação Avançada, utilize o React Three Fiber se você usa React, e mantenha a performance sob controle com o guia de Web Performance. Depois, construa a menor cena possível — um cubo iluminado ao redor do qual você possa orbitar — e a expanda conceito por conceito.