Trucos de animación con suavizado exponencial
- Hay una técnica de animación simple que he usado casi siempre desde que empecé a trabajar en cosas relacionadas con animación.
- Esta técnica se usa en muchos lugares: rotación y movimiento de cámara, movimiento de personajes en juegos por turnos, desplazamiento de elementos de UI, suavizado de cambios de volumen en bibliotecas de audio, entre otros.
- La técnica no es nueva; puede que ya la hayas escuchado o usado, pero voy a explicar algunos ejemplos y el principio matemático detrás.
Botón de alternancia
- Al crear un componente de UI, por ejemplo, supongamos que hacemos un botón de alternancia.
- La posición del interruptor del botón se calcula según el estado: si está encendido, se establece en
max_x; si está apagado, en min_x.
- Este enfoque funciona bien, pero sin animación se ve algo sin vida.
- La animación no solo añade atractivo visual, también ayuda a que el usuario entienda qué está ocurriendo.
- En vez de mover el indicador del botón inmediatamente a su nueva posición, se cambia para que se desplace suavemente.
- Ahora hay que actualizar la animación, pero esto tiene la desventaja de que parece moverse a velocidad constante.
- Aquí se puede añadir una función de easing, por ejemplo
3t^2-2t^3 o una función como sqrt(t).
- Las diferencias entre estas funciones de easing se notan mejor cuando la animación se reproduce lentamente.
- Ahora, en lugar de actualizar la posición del interruptor, hay que rastrear el estado de la animación.
- Al usar
sqrt, hay que usar explícitamente funciones de easing distintas según la dirección de la animación.
- Cuál se ve mejor depende del gusto, pero
sqrt es el que se ve mejor. Hace que el interruptor empiece muy rápido, pero desacelere bien al acercarse a su destino.
- La desventaja de esta versión es que requiere bastante manejo incluso en el caso más simple, y si el usuario hace clic a mitad de la animación aparece una discontinuidad con un salto repentino.
Movimiento de cámara
- Supongamos una situación en la que el mapa y la cámara se desplazan o se mueven por el entorno.
- También aquí conviene añadir animación.
- Se presenta código que interpola a velocidad constante.
- La vibración que aparece después de completar la animación ocurre porque
target.x - position.x va alternando entre valores positivos y negativos.
- En lugar de
sign(delta), hace falta una función que limite el delta.
- Este método es bastante complicado para algo sencillo.
- Se ve raro cuando la velocidad de la animación es más rápida que la finalización de la animación.
- También se podría ignorar la entrada del usuario mientras la animación está activa, pero eso produce una experiencia muy frustrante.
- La solución perfecta es, por supuesto, el suavizado exponencial.
- El código casi no cambia comparado con el ejemplo del botón de alternancia.
Cómo funciona por dentro
- Se explica qué es
1 - exp(- speed * dt) y cómo funciona.
- Empezando por la versión simple, se hace que la velocidad sea proporcional a la distancia entre la
position actual y la nueva posición target, para que el movimiento sea más rápido.
- Este método no necesita mantener ningún estado aparte de la posición actual y la posición objetivo, y se ajusta automáticamente aunque
target cambie de golpe.
- Pero hay un pequeño problema: si
speed * dt es mayor que 1, la posición se pasa del objetivo.
- Para resolver esto, se puede limitar el valor a 1.
- La razón por la que
speed * dt es demasiado grande es que el valor de speed es demasiado alto o dt es demasiado grande.
- Para animación, sería ideal que todo funcionara perfectamente al aplicar
dt.
Ecuaciones diferenciales (oh, no)
- Se presenta un enfoque de dos pasos para resolver el problema.
- Que
position += (target - position) * speed * dt funcione para valores pequeños de dt pero falle para valores grandes de dt es un problema típico de los métodos numéricos para resolver ecuaciones diferenciales.
- Se analiza qué resuelve esta ecuación.
- Se explica que
position += (target - position) * (1 - exp(- speed * dt)) es la fórmula correcta para cualquier dt.
Elegir la velocidad
- Normalmente se piensa en la animación en términos de duración.
- Al usar la fórmula exponencial, técnicamente la animación nunca termina y se completa en un tiempo infinito.
- Lo que significa el parámetro
speed es que 1 / speed es el tiempo en el que position se acerca a target por un factor de e = 2.71828....
Suavizado exponencial
- Si buscas "suavizado exponencial", puedes encontrar un artículo de Wikipedia que parece totalmente no relacionado, pero en realidad incluye una fórmula muy similar a la discutida en esta publicación.
- Si se asume que
dt siempre es el mismo y que target cambia en cada iteración, se indexan los valores por número de iteración para calcular algo como position[i] = (target[i] - position[i - 1]) * factor.
Título del último párrafo
- Tuve la idea para esta publicación durante varios meses, y me alegra haberla terminado por fin.
- Gracias por ver y leer el registro de desarrollo.
Opinión de GN⁺
- Este artículo explica la técnica de suavizado exponencial, utilizada para hacer que las animaciones se vean más fluidas y naturales. Esta técnica contribuye a mejorar la experiencia de usuario y a aumentar la intuición de la interfaz.
- El suavizado exponencial también puede ser útil para simular movimiento físico; por ejemplo, en desarrollo de juegos se puede usar para que el movimiento de personajes o de la cámara se vea más natural.
- Esta técnica es especialmente efectiva cuando elementos de la interfaz de usuario atraviesan cambios de estado, ya que permite representar esos cambios visualmente de forma muy suave. Por ejemplo, puede hacer que el movimiento de sliders o interruptores se vea más fluido.
- Desde una mirada crítica, el suavizado exponencial puede dificultar el control preciso de la velocidad y la duración de una animación. Esto puede ser una limitación cuando un diseñador quiere ajustar con precisión un efecto de animación específico.
- Otras bibliotecas o frameworks de animación que ofrecen funciones similares incluyen GreenSock Animation Platform(GSAP) y anime.js, que proporcionan un control más detallado de las animaciones junto con varias funciones de easing.
- Al adoptar la técnica de suavizado exponencial, hay que encontrar un equilibrio entre la naturalidad de la animación y la precisión del control. La ventaja de elegir esta técnica es la mejora de la experiencia de usuario; la desventaja es que puede ser difícil ajustar con precisión el timing de la animación.
1 comentarios
Opiniones de Hacker News
Resumen del primer comentario:
smoothstep(), sino un método sin estado (stateless) que maneja entradas diversas de forma consistente.exponential smoothing) tiene el problema de que se acerca al destino pero nunca lo alcanza.inertial scrolling), se menciona que fue útil añadir un término de fricción (falsa).Resumen del segundo comentario:
exponential lerp) es útil pero poco conocido, y en algunos juegos se usa una interpolación lineal menos precisa, lo que causa problemas de animación.Resumen del tercer comentario:
sqrt) es mejor que una cúbica (cubic) para un interruptor de palanca.Resumen del cuarto comentario:
Resumen del quinto comentario:
lazy-easy.Resumen del sexto comentario:
Resumen del séptimo comentario:
Resumen del octavo comentario:
Resumen del noveno comentario:
Resumen del décimo comentario: