45. Interpolación y movimiento suave

Interpolar significa construir estados intermedios. Con una sola idea podemos mover objetos, mezclar colores, orientar cámaras, suavizar interfaces y diseñar ritmos de animación controlables.

45.1 Introducción

Una animación conecta valores a lo largo del tiempo. Entre una posición inicial y otra final necesitamos decidir no solo dónde está el objeto, sino también cómo cambia su velocidad.

La interpolación lineal proporciona la trayectoria básica; las funciones de easing modifican el progreso para conseguir movimientos naturales y expresivos.

45.2 Interpolación lineal

Dados A, B y un parámetro t:

lerp(A,B,t)=A+(B−A)t=(1−t)A+tB

Cuando t=0 obtenemos A; con t=1 obtenemos B; con t=0.5 aparece el punto medio.

45.3 Interpretación de t

t=0
inicio
0<t<1
interpolación
t=1
final
t fuera de [0,1]
extrapolación

Limitar t con Math.max(0,Math.min(1,t)) evita superar el intervalo cuando el comportamiento requiere extremos fijos.

45.4 Ejemplo numérico

Para A=10, B=30 y t=0.25:

10+(30−10)·0.25=15

Hemos recorrido el 25% de la diferencia. La operación funciona igual con valores negativos y magnitudes físicas compatibles.

45.5 Interpolar puntos y vectores

P(t)=(Ax+(Bx−Ax)t, Ay+(By−Ay)t)

Cada componente usa el mismo t. El resultado recorre el segmento AB con velocidad constante respecto del parámetro.

45.6 Duración y tiempo normalizado

Si una animación comienza en instante inicio y dura D segundos:

t=(ahora−inicio)/D

El tiempo normalizado separa la duración real de la forma de la animación. Una misma curva puede durar medio segundo o diez segundos.

45.7 Velocidad constante

Lerp con t creciendo linealmente produce velocidad constante:

velocidad=|B−A|/D

El objeto comienza y termina de forma instantánea. Es adecuado para cintas transportadoras o indicadores técnicos, pero puede parecer rígido en una interfaz.

45.8 Easing

Una función de easing transforma el progreso antes de interpolar:

valor=lerp(A,B,easing(t))
ease-in
acelera desde el reposo
ease-out
frena al llegar
ease-in-out
acelera y luego frena

45.9 Funciones frecuentes

easeIn(t)=t²
easeOut(t)=1−(1−t)²
smoothstep(t)=t²(3−2t)

Smoothstep tiene pendiente cero en ambos extremos. Esto elimina cambios bruscos de velocidad al comenzar y terminar.

45.10 Suavizado iterativo

Es común acercar repetidamente un valor a su objetivo:

actual=lerp(actual,objetivo,α)

Este patrón no llega en un tiempo fijo: recorre una fracción de la distancia restante en cada actualización. Produce una aproximación exponencial.

45.11 El problema del frame rate

Usar un α fijo por fotograma hace que el resultado dependa de cuántos cuadros se ejecuten. Para una rapidez λ y delta time Δt se utiliza:

α=1−e−λΔt

Así, la respuesta después de un segundo es prácticamente igual a 30, 60 o 144 FPS.

45.12 Interpolar ángulos

Entre 350° y 10° el camino corto mide 20°, no −340°. Primero se normaliza la diferencia al intervalo [−180°,180°):

diferencia=((B−A+180) mod 360)−180
ángulo=A+diferencia·t

El mismo principio se aplica en radianes usando π y 2π.

45.13 Laboratorio interactivo de easing

Compara el progreso lineal con varias curvas. La gráfica muestra la función y la nave utiliza exactamente el mismo valor de t transformado.

tf(t)t = 0.00f(t) = 0.00posición = 0.00

45.14 Lerp y easing en JavaScript

const lerp=(a,b,t)=>a+(b-a)*t;
const limitar01=t=>Math.max(0,Math.min(1,t));
const smoothstep=t=>{
  t=limitar01(t);
  return t*t*(3-2*t);
};

const inicio={x:10,y:20};
const fin={x:110,y:60};
const t=smoothstep(0.35);
const posicion={
  x:lerp(inicio.x,fin.x,t),
  y:lerp(inicio.y,fin.y,t)
};
console.log(posicion);

El código muestra una posición intermedia usando progreso suavizado y es completamente autocontenido.

45.15 Seguimiento independiente del frame rate

function seguir(actual,objetivo,rapidez,dt) {
  const factor=1-Math.exp(-rapidez*dt);
  return actual+(objetivo-actual)*factor;
}

let posicion=0;
const objetivo=100;
for (let cuadro=1;cuadro<=5;cuadro++) {
  posicion=seguir(posicion,objetivo,4,1/60);
  console.log(`Cuadro ${cuadro}: ${posicion.toFixed(2)}`);
}

La rapidez controla la respuesta por segundo. Multiplicar directamente una fracción fija no ofrece esta estabilidad temporal.

45.16 Interpolación angular en JavaScript

function lerpAngulo(a,b,t) {
  const diferencia=((b-a+180)%360+360)%360-180;
  return a+diferencia*t;
}

console.log(lerpAngulo(350,10,0.5)); // 360, equivalente a 0°
console.log(lerpAngulo(10,350,0.5)); // 0°

La normalización doble del módulo también funciona cuando la diferencia inicial es negativa.

45.17 Aplicación animada: cámara cinematográfica

Una cámara sigue a una nave con suavizado exponencial. El objetivo cambia de rumbo, la cámara amortigua el movimiento y el indicador compara ambas posiciones.

Error de seguimiento: 0Factor del cuadro: 0

45.18 Aplicaciones, errores y conclusión

La interpolación se utiliza en cámaras, menús, barras de progreso, transiciones, zoom, colores, orientación, movimiento de personajes, indicadores y sincronización de estados.

  • No limitar t cuando la animación debe permanecer entre extremos.
  • Usar un factor fijo por cuadro y depender del frame rate.
  • Confundir duración con rapidez de aproximación exponencial.
  • Interpolar ángulos sin buscar el camino más corto.
  • Aplicar easing a la posición acumulada en lugar del tiempo normalizado.
  • Reiniciar el origen de una interpolación cada cuadro.
  • Esperar que lerp iterativo alcance exactamente el objetivo.
  • Usar easing con saltos o valores fuera del intervalo sin intención.

Recuerda: lerp mezcla extremos; t describe progreso; easing modifica el ritmo; y el factor 1−e−λΔt produce seguimiento estable frente a variaciones del frame rate.

En el próximo tema estudiaremos curvas de Bézier y trazado de curvas.