Animación Esquelética por WebGL

La animación esquelética es un proceso para animar cuerpos articulados mas complejos que un simple movimiento uniforme durante una animación. Para lograr esto se modela el cuerpo (comúnmente en la mitad de los casos) ubicando nodos en la articulación, ocasionando que lo único que se tenga que animar sea estos nodos, asignándoles una ubicación especifica en un frame especifico

Animation tutorial de ThinMatrix 5

A continuación continuación se puede encontrar un claro ejemplo del resultado de esta metodología. [1][2] El modelo 3D de un vaquero modelado por Blendr[3] se encarga de animarlo para simular que se encuentra caminando.

Metodología del algoritmo

En este ejemplo no se usa ningún JS a pesar que si tienen algunas dependencias. Incluso el JSON importado se encuentra quemado en el mismo código. Esto se puede usar a nuestro favor ya que hasta el código de los scripts externos se encuentran acá implementados. Como el código fue desarrollado con Node.js la sintaxis del script suele ser bastante distinta. Por ejemplo cada método o módulo tiene un índice asociado. Asi que si un módulo necesita a otro, ubica las dependencias y su respetivo índice al final de si mismo.

Dependencias del módulo draw

Entrando más en detalle, todo inicia en el método 2 en donde crea el canvas y el componente gl del browser. También crea el slider que permite acelerar o ralentizar la animación. Importa el JSON del vaquero desde el índice 1.

Exploración del JSON

El vaquero viene del formato COLLADA (.DAE) el cual tuvo que ser convertido a un JSON para poderlo parametrizar a punta de nodos en las articulaciones. El archivo, disponible en este repositorio, tiene los siguientes atributos:

Atributo Cantidad Utilidad
Articulaciones 18 Nombre y posición de cada articulación
Frames 24 x 18 x 16 Distribuidos en {0.0, 6.25} con una matriz 4x4 para cada articulación.
Posiciones 729 * 3 Flotantes seguidos representando las posiciones de cada vértice
Articulaciones por vértice 729 x N x 1 Asocia 2 ó más articulaciones ponderadas a cada vértice para asignar una fuerza al momento de moverlo (arrastrarlo) durante el movimiento.
Indices por triangulo 1440 * 3 Orden de los vértices para pintar todos los triángulos
Normales 1440 * 3 Flotantes agrupados entre 3 para determinar las normales de cada cara. Necesarios para calcular la intensidad de luz a cada cara
Coordenadas UV 1440 * 3 * 2 Coordenadas para mapear la máscara de la textura en cada vértice del personaje

Conversión de matriz 4x4 a cuaterniones duales

Como vimos antes, el JSON tiene la matriz de cada articulación en cada keyframe. No obstante, Nwafili las convierte a cuaterniones. Presenta el estudio en que una animación casi en tiempo real puede traer unas deformaciones potenciales al tratar matrices 4x4. [3] Como se sabe el uso de cuaterniones son una forma de manejar rotaciones más confiables. En este caso también las usa para representar la traslación de cada articulación. En resumen, el arreglo de 16 flotantes que representaba una matriz es transformado a un arreglo de 8: los primeros 4 para la rotación, los últimos para la traslación. (28)

Conversión matriz a cuaternión doble

Ahora es necesario convertir todas las matrices de todos las uniones a cuaterniones duales (19) la cual es un simple recorrido por todo el atributo de frames del JSON

Carga del archivo COLLADA su textura y todo el shader en JS

La funcion loadCollada (24) no solo se encarga principalmente de cargar el DAE exportado sino también de cargar todo el shader programa con todos los atributos de cada triangulo próximo a pintar y guardarlo en la variable cowboyModel.
Entrando más en detalle lee todos los atributos del JSON y asigna cada uno a un arreglo específico (22)


Compila los shaders (26) a partir de los strings en GLSL del vertex shader (27) y el fragment shader (25). Crea los buffers y le pasa a los atributos ya leídos del JSON. Por otro lado carga la textura (23) asignando las coordenadas del atributo de coordenadas UV. Finalmente retorna el resultado de createDrawFunction() (21) que trata del string en Javascript necesario para asignar todas las variables uniformes y pintar vértice por vértice y triángulo por triángulo el personaje con su respectiva textura.


Interpolación de las articulaciones

Como ya están las ubicaciones de las articulaciones pero de solo 24 keyframes específicos, para determinar los datos en un tiempo específico se interpolan las posiciones a partir del anterior y próximo keyframe conocido. Esto es posible mezclando los dos pares de cuaterniones (34) interpolándolos con un factor entre 0 y 1.



En ese orden de ideas en la siguiente línea se pueden determinar las posiciones de las 18 articulaciones (33, 36) en un tiempo específico a partir del anterior keyframe y el próximo.


Ya con los cuaterniones de las articulaciones (uno para rotación, el otro para traslación) del tiempo actual se pasan como variables uniformes para que los vértices sean ubicados usando de referencia las 18 uniones. Finalmente se pasan al draw() (21) resultado de cowboyModel (24) para que sea dibujados. Esto ya que tiene los únicos datos que le faltaban adquirir para pintar todos los triángulos en el keyframe actual.

Renderizado en bucle

Utilizando la función raf loop (30) permite renderizar en un bucle tomando en cuenta la clase Engine basado en el cálculo del tiempo (32), en el script raf (31) y el manejo de eventos del tipo eventListener (37) Todo esto con el apoyo de Node.js (18)

En este repositorio se encuentran los comentarios en español sobre la mayoría de las funciones en español bajo el tag drmayo Los métodos o líneas de código donde se define la animación están bajo el tag @relevante. El seguimiento del trabajo realizado se encuentra en este sprint .


Bibliografia:
  1. Nwafili C. F. WebGL Skeletal Animation Tutorial 2017
  2. GitHub - chinedufn skeletal-animation-system repository 2017
  3. Lague S. Blender Character Creation 2015
  4. Kavan Ladislav et. al. Skinning wit Dual Quaternions 2007
  5. GitHub - damayor skeletal-animation-system repository 2018

Comentarios

Entradas populares