Animación
Este post se enfocará en lograr que un objeto no-simétrico siga una curva de bezier.
El resultado final de lo que se estará implementando se encuentra aquí, mientras que el código se puede encontrar acá.
Nos concentraremos en los segmentos de código relevantes a la animación. No se discutirá como se definieron los vertices para crear la figura que se desplaza en el canvas.
Inicialmente, para definir la curva de bezier que vamos a seguir con nuestra figura hacemos uso de la librería bezier.js. Esta nos permite obtener los puntos que conforman una curva cúbica de bezier en tres dimensiones.
Para crear la curva que vamos a trazar recurrimos al siguiente método:
Los 4 parámetros que se le pasan a esta función son los 4 puntos (x, y, z) que definen a una curva de bezier cúbica.
El resultado final de lo que se estará implementando se encuentra aquí, mientras que el código se puede encontrar acá.
Nos concentraremos en los segmentos de código relevantes a la animación. No se discutirá como se definieron los vertices para crear la figura que se desplaza en el canvas.
Inicialmente, para definir la curva de bezier que vamos a seguir con nuestra figura hacemos uso de la librería bezier.js. Esta nos permite obtener los puntos que conforman una curva cúbica de bezier en tres dimensiones.
Para crear la curva que vamos a trazar recurrimos al siguiente método:
Los 4 parámetros que se le pasan a esta función son los 4 puntos (x, y, z) que definen a una curva de bezier cúbica.
- La primera linea de la función crea una nueva curva de bezier utilizando la librería.
- La segunda linea nos crea una Look Up Table sobre esa curva, esto es un arreglo que contiene 100 puntos (x, y, z) que describen la curva de bezier.
- La tercera linea establece que estamos situados en el primer nodo del arreglo que creamos en el punto anterior.
- La cuarta linea establece que la posición actual de nuestra figura debe ser la posición del primer nodo de nuestra curva de bezier.
- La quinta linea establece a que nodo se debe estar acercando nuestra figura en las siguientes iteraciones. En este caso es el nodo que le sigue al nodo inicial.
El siguiente componente importante de nuestra animación se encuentra en la función drawScene:
Se destacan 3 elementos importantes en esta función: las transformaciones aplicadas al world matrix, la dibujada de nuestra figura (en este caso una L), y el llamado a la función followPath.
- El world matrix es una matriz que se le va a aplicar a todos los elementos que vamos a dibujar. Dado que vamos a estar moviendo toda nuestra figura en cada frame para realizar la animación, aquí es el lugar donde aplicamos la translación a la posición definida por la variable position. Adicionalmente, como queremos que nuestro objeto esté apuntando siempre hacia el camino que está recorriendo, utilizamos la función targetTo que direcciona nuestra figura apropiadamente.
- El método drawL dibuja la L que vamos a estar moviendo. Le pasamos por parámetro el worldMatrix para que se le aplique a esta figura las transformaciones que discutimos.
- El método followPath es el que actualiza las variables que hacen que el movimiento de nuestra figura siga la curva de bezier.
La última función que hay que entender para saber como está funcionando nuestra animación es followPath.
Este es el corazón de la animación. El parámetro que recibe la función indica cuanto tiempo ha pasado desde que procesamos el último frame. Adicionalmente, la función se encarga de:
- Primero revisa si ya estamos en el último nodo que describe nuestra curva de bezier, de ser cierto ya terminamos la animación y dejamos de actualizar valores. De lo contrario seguimos.
- Sacamos del arreglo de nodos el nodo que estamos persiguiendo actualmente, es decir, nuestro target. Convertimos este objeto a un vec3 para realizar más cómodamente las operaciones entre vectores.
- Revisamos si la distancia entre la posición de nuestra figura y el target es menor que una distancia arbitraria. Esta tiene que ser lo suficientemente pequeña para que nuestra figura tenga que estar bastante cerca al target antes de cambiarlo. Ya que estamos trabajando sobre coordenadas entre -1 y 1, se escogió el valor de 0.1. Si se cumple esta condición cambiamos el target que está persiguiendo nuestra figura.
- Encontramos el vector velocidad, que es el que indica en que dirección se debe mover nuestra figura para acercarse a nuestro target. Esto se logra haciendo la resta entre el target y la posición actual de nuestro objeto. Luego, multiplicamos el vector resultante por el deltaTime para que nos movamos proporcional al tiempo entre frames.
- Finalmente, agregamos a nuestra posición el vector velocidad para acercarnos un poco más a nuestro target.
Bitácora de Tiempo
Para la realización de este ejercicio se esperaba invertir al rededor de 8 horas de tiempo. Sin embargo, me terminó costando mucho más que esto (al rededor de 13 horas). La mayoría del tiempo se fue tratando de entender bien el funcionamiento de las curvas de bezier, el movimiento del objeto, y como perfilarlo hacia un objetivo. El bug que más me costó fue que estaba utilizando la función lookAt de mat4, mientras que la que debía estar usando era targetTo.
Comentarios
Publicar un comentario