Animaciones
El Latido del Mundo
Un mundo estático en 3D es solo una fotografía aburrida. Para que las cosas se sientan vivas y dinámicas (un molino girando, partículas flotando, naves avanzando), necesitamos el concepto de Game Loop o Bucle de Animación.
requestAnimationFrame
En el capítulo de Keyframes, dejábamos que CSS calculara todo. En WebGL, tú eres el dueño del bucle. El navegador nos ofrece la función requestAnimationFrame(funcion). Su única tarea es llamar a una función justo antes de pintar el siguiente frame de la pantalla. Si tu pantalla corre a 60 hercios (60 fps), llamará a tu función 60 veces por segundo.
El problema de los FPS
Si simplemente sumas mesh.rotation.y += 0.01 en cada frame, y mi ordenador es potentísimo corriendo a 144 fps, mi cubo girará al doble de velocidad que el tuyo si tu pantalla es de 60 fps. Esto arruina las experiencias jugables o sincrónicas.
Clock al rescate
Para solucionar que la velocidad dependa del hardware, Three.js trae THREE.Clock(). En lugar de sumar un número fijo cada frame, le preguntas al reloj "¿Cuánto tiempo (Delta) ha pasado desde el frame anterior?". Multiplicas tu movimiento por ese tiempo. Así, tu cubo girará siempre a 90 grados por segundo de forma real, ya sea en un iPhone 8 o en una PC Gamer de 5000 dólares.
Consejo profesional
GSAP se lleva maravillosamente bien con Three.js. Puedes usar gsap.to(mesh.position, { x: 5, duration: 2 }) para animar cosas a lugares exactos con easings, mientras requestAnimationFrame se encarga solo de mantener el renderizado activo.
El bucle perfecto usando Delta Time
// 1. Instanciamos el Reloj
const clock = new THREE.Clock();
function animate() {
// Solicitamos el próximo frame inmediatamente
requestAnimationFrame(animate);
// Obtenemos el tiempo transcurrido desde el último frame
const elapsedTime = clock.getElapsedTime(); // Tiempo total
const deltaTime = clock.getDelta(); // Tiempo entre frames
// Rotación basada en el tiempo total (ideal para movimientos cíclicos continuos)
mesh.rotation.y = elapsedTime * Math.PI * 0.5; // Medio giro por segundo
// Oscilación estilo flotación con funciones trigonométricas
mesh.position.y = Math.sin(elapsedTime * 2) * 0.5;
// Renderizado final
renderer.render(scene, camera);
}
animate(); Una geometría flotando suavemente, usando Math.sin() impulsado por el reloj.
Errores comunes
Practica lo aprendido
Domina el movimiento basado en tiempo.