Escenas · Cámaras · Geometrías · Materiales · Luces · OrbitControls
Three.js es una librería JavaScript de código abierto que permite crear y mostrar gráficos 3D en el navegador. Internamente usa WebGL, la API del navegador para gráficos de alto rendimiento por GPU, pero nos oculta toda su complejidad.
WebGL puro requiere escribir shaders en GLSL, gestionar buffers de vértices, matrices de transformación y mucho más. Three.js abstrae todo eso: creas objetos con código JavaScript legible y la librería traduce todo a WebGL por ti.
Todos los elementos de Three.js se organizan en una estructura de árbol:
Three.js se puede incluir de dos formas: via CDN con un
<script> clásico, o usando ES Modules
con import. En proyectos modernos se prefieren los módulos.
<!-- 1. Declara el mapa de importaciones en el <head> -->
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/"
}
}
</script>
<!-- 2. En el script, importa lo que necesites -->
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// Tu código Three.js va aquí...
</script>
<!-- El canvas es donde Three.js dibuja. Puede ir en cualquier parte del body. -->
<canvas id="mi-canvas"></canvas>
<!-- Estilos para que el canvas ocupe toda la ventana -->
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { overflow: hidden; background: #000; }
canvas { display: block; }
</style>
Estos tres elementos son el mínimo imprescindible de cualquier proyecto Three.js. Sin los tres no hay nada que mostrar.
import * as THREE from 'three';
// ── 1. ESCENA ─────────────────────────────────────────────────
// La escena es el "mundo" donde colocamos todos los objetos.
const scene = new THREE.Scene();
scene.background = new THREE.Color('#0a0a12'); // color de fondo
// ── 2. CÁMARA ─────────────────────────────────────────────────
// PerspectiveCamera simula perspectiva humana (objetos lejanos son más pequeños).
// Parámetros: fov (campo visual°), aspect (ancho/alto), near, far
const camera = new THREE.PerspectiveCamera(
75, // FOV: 75° es un valor natural
window.innerWidth / window.innerHeight, // relación de aspecto
0.1, // plano cercano (near)
1000 // plano lejano (far)
);
camera.position.set(0, 2, 5); // posición X, Y, Z en el espacio 3D
camera.lookAt(0, 0, 0); // apunta al origen
// ── 3. RENDERER ───────────────────────────────────────────────
// WebGLRenderer dibuja la escena en un elemento
const renderer = new THREE.WebGLRenderer({
canvas: document.getElementById('mi-canvas'),
antialias: true // suaviza los bordes (antialiasing)
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio); // resolución en pantallas Retina
// ── 4. PRIMER RENDER ──────────────────────────────────────────
renderer.render(scene, camera); // dibuja UNA vez
Three.js incluye muchas geometrías listas para usar. Todas heredan de
BufferGeometry y definen la forma de un objeto mediante
vértices, aristas y caras.
// ── GEOMETRÍAS PRIMITIVAS ─────────────────────────────────────
// Cada geometría define la forma matemática del objeto.
const cubo = new THREE.BoxGeometry(1, 1, 1); // ancho, alto, profundidad
const esfera = new THREE.SphereGeometry(0.5, 32, 32); // radio, seg. horizontales, verticales
const plano = new THREE.PlaneGeometry(10, 10); // ancho, alto
const cilindro = new THREE.CylinderGeometry(0.5, 0.5, 2, 32); // radioTop, radioBot, h, seg
const toro = new THREE.TorusGeometry(0.5, 0.2, 16, 100); // radio, tubo, seg, seg
const cono = new THREE.ConeGeometry(0.5, 1, 32); // radio, altura, segmentos
// ¡Más segmentos = más suave, pero más costoso computacionalmente!
// SphereGeometry(0.5, 8, 8) → rugosa. SphereGeometry(0.5, 64, 64) → perfecta.
El material define el aspecto visual del objeto. Algunos materiales
reaccionan a la luz, otros no. Si usas MeshStandardMaterial
y no hay luces en la escena, el objeto se verá completamente negro.
| Material | Necesita luz | Uso típico |
|---|---|---|
MeshBasicMaterial |
No | Pruebas, wireframes, iconos. Siempre visible. |
MeshNormalMaterial |
No | Depuración. Colorea las normales de la geometría. |
MeshLambertMaterial |
Sí | Superficies mate sin reflejos especulares. Rápido. |
MeshPhongMaterial |
Sí | Superficies con brillo especular. Plástico, metal básico. |
MeshStandardMaterial |
Sí | Recomendado. PBR: roughness + metalness. Más realista. |
MeshPhysicalMaterial |
Sí | PBR avanzado: vidrio, refracción, clearcoat. |
// ── MATERIALES ────────────────────────────────────────────────
// MeshBasicMaterial: no reacciona a la luz, color plano
const matBasico = new THREE.MeshBasicMaterial({
color: '#ff6b35',
wireframe: false // true → muestra solo las aristas
});
// MeshStandardMaterial: PBR (Physically Based Rendering)
// Necesita al menos una luz para verse correctamente.
const matStandard = new THREE.MeshStandardMaterial({
color: '#4aa8ff', // color base
metalness: 0.3, // 0 = plástico, 1 = metal puro
roughness: 0.4 // 0 = espejo, 1 = completamente rugoso
});
// ── LUCES ─────────────────────────────────────────────────────
// AmbientLight: ilumina uniformemente todo, sin dirección ni sombras
const luzAmbiente = new THREE.AmbientLight('#ffffff', 0.5); // color, intensidad
scene.add(luzAmbiente);
// DirectionalLight: como el sol, rayos paralelos, produce sombras
const luzDireccional = new THREE.DirectionalLight('#ffffff', 1.5);
luzDireccional.position.set(5, 10, 7); // posición de la fuente de luz
scene.add(luzDireccional);
// PointLight: como una bombilla, emite en todas las direcciones
const luzPunto = new THREE.PointLight('#ff6b35', 2, 10); // color, intensidad, distancia
luzPunto.position.set(-3, 2, 2);
scene.add(luzPunto);
Todo objeto 3D en Three.js (Mesh, Camera, Light…) tiene tres propiedades
de transformación: position, rotation y scale.
Las tres son objetos THREE.Vector3 con ejes X, Y y Z.
// ── TRANSFORMACIONES DE UN MESH ───────────────────────────────
const mesh = new THREE.Mesh(geometria, material);
// POSICIÓN — en unidades de la escena (1 unit ≈ 1 metro)
mesh.position.set(2, 0, -1); // x, y, z
mesh.position.x = 2; // también se puede eje a eje
// ROTACIÓN — en radianes (Math.PI = 180°)
mesh.rotation.set(0, Math.PI / 4, 0); // 45° sobre el eje Y
mesh.rotation.y += 0.01; // acumular en cada frame → gira
// ESCALA — 1 = tamaño original
mesh.scale.set(2, 1, 0.5); // doble en X, mitad en Z
mesh.scale.setScalar(1.5); // escala uniforme
// JERARQUÍAS — agrupar objetos para transformarlos juntos
const grupo = new THREE.Group();
grupo.add(mesh1);
grupo.add(mesh2);
grupo.position.y = 2; // mueve ambos meshes juntos
scene.add(grupo);
// CONVERSIÓN: grados → radianes
// const rad = THREE.MathUtils.degToRad(45); // → 0.785...
OrbitControls es un add-on de Three.js (no está en el bundle
principal) que agrega navegación 3D interactiva: orbitar con el mouse,
hacer zoom con la rueda y hacer panning con el botón derecho.
// ── IMPORTAR ORBITCONTROLS (es un add-on, no parte del core) ──
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// ── CREAR E INICIALIZAR ────────────────────────────────────────
const controls = new OrbitControls(camera, renderer.domElement);
// domElement es el
// ── OPCIONES COMUNES ──────────────────────────────────────────
controls.enableDamping = true; // inercia suave al soltar el mouse
controls.dampingFactor = 0.05; // qué tan rápido frena (0.05 es suave)
controls.enableZoom = true; // zoom con rueda del mouse
controls.enablePan = true; // panning con botón derecho
controls.autoRotate = false; // rotación automática continua
controls.autoRotateSpeed= 2.0; // velocidad de autoRotate
controls.minDistance = 2; // distancia mínima de zoom
controls.maxDistance = 20; // distancia máxima de zoom
controls.maxPolarAngle = Math.PI / 2; // ángulo vertical máximo (no gira debajo)
// ── MUY IMPORTANTE: actualizar en el loop ─────────────────────
// Si enableDamping = true, DEBES llamar controls.update() en cada frame
function animate() {
requestAnimationFrame(animate);
controls.update(); // ← obligatorio con damping
renderer.render(scene, camera);
}
animate();
Controles del mouse con OrbitControls:
• Botón izquierdo + arrastrar → orbitar (rotar la cámara alrededor)
• Rueda del mouse → zoom in/out
• Botón derecho + arrastrar → panning (mover la cámara lateralmente)
• Dos dedos en touch → zoom. Un dedo → orbitar
requestAnimationFrame es la API del navegador para crear loops
de animación sincronizados con la pantalla (60fps o más). Three.js lo usa
internamente para mantener la escena en movimiento.
// ── EL LOOP DE ANIMACIÓN ──────────────────────────────────────
// requestAnimationFrame llama a la función antes de cada repintado
// de la pantalla (60fps en la mayoría de monitores).
// La función se llama a sí misma para crear el loop infinito.
const clock = new THREE.Clock(); // para medir el tiempo transcurrido
function animate() {
requestAnimationFrame(animate); // ← pide el próximo frame
const elapsed = clock.getElapsedTime(); // segundos desde que empezó
const delta = clock.getDelta(); // tiempo entre el frame anterior y este
// ── Rotar el cubo en cada frame ──
cubo.rotation.x += 0.01; // velocidad en radianes/frame
cubo.rotation.y += 0.01;
// ── Animación con seno (oscilación suave) ──
esfera.position.y = Math.sin(elapsed * 2) * 0.5; // sube y baja
// ── Actualizar controles (si tienen damping) ──
controls.update();
// ── Renderizar la escena ──
renderer.render(scene, camera);
}
animate(); // ← arrancar el loop
// ── RESPONSIVE: adaptar al cambio de tamaño de ventana ────────
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix(); // obligatorio tras cambiar aspect
renderer.setSize(window.innerWidth, window.innerHeight);
});
Construye una escena 3D completa usando todos los conceptos de la semana: múltiples objetos, materiales con luz, navegación con OrbitControls y al menos un objeto animado en el loop.
Scene, PerspectiveCamera, WebGLRenderer con antialias.
AmbientLight y al menos una DirectionalLight o PointLight.
OrbitControls con enableDamping: true para navegación suave.
resize listener que actualiza cámara y renderer.
💡 Recursos clave: Documentación oficial de Three.js · Ejemplos oficiales · Discover Three.js (libro gratuito). El inspector de escena Three.js Developer Tools para Chrome es muy útil para depurar.