Neste artigo descreverei minha compreensão da animação esquelética, que é usada em todos os motores 3D modernos para animar personagens, ambientes de jogos, etc.
Começarei a descrição com a parte mais tangível – sombreador de vértice, pois todo o caminho de cálculo, por mais complexo que seja, termina com a transferência dos dados preparados para exibição para o sombreador de vértice.

A animação do esqueleto, após ser processada na CPU, vai para o vertex shader.
Deixe-me lembrá-lo da fórmula para vértice sem animação esquelética:
gl_Position = projeçãoMatrix * viewMatrix * modelMatrix * vértice;
Para quem não entende como surgiu essa fórmula, pode ler meu artigo que descreve o princípio de trabalhar com matrizes para exibição de conteúdo 3D no contexto do OpenGL.
Quanto ao resto – fórmula para implementar animação esquelética:
” vec4 animadoVertex = bone0matrix * vértice * bone0weight +”
“bone1matrix * vértice * bone1weight +”
“bone2matrix * vértice * bone2weight +”
“bone3matrix * vértice * bone3weight;\n”
” gl_Position = projeçãoMatrix * viewMatrix * modelMatrix * animadoVertex;\n”
Ou seja, multiplicamos a matriz de transformação óssea final pelo vértice e pelo peso desta matriz em relação ao vértice. Cada vértice pode ser animado por 4 ossos, a força do impacto é regulada pelo parâmetro peso do osso, a soma dos impactos deve ser igual a um.
O que fazer se menos de 4 ossos afetarem o vértice? Precisamos dividir o peso entre eles e fazer com que o impacto do restante seja igual a zero.
Matematicamente, multiplicar um peso por uma matriz é chamado de “multiplicação escalar de matriz”. Multiplicar por um escalar permite resumir o efeito das matrizes no vértice resultante.
As próprias matrizes de transformação óssea são transmitidas como uma matriz. Além disso, a matriz contém matrizes para todo o modelo como um todo, e não para cada malha separadamente.
Mas para cada vértice as seguintes informações são transmitidas separadamente:
– Índice da matriz que afeta o vértice
– Peso da matriz que afeta o vértice
Mais de um osso é transmitido, geralmente é utilizado o efeito de 4 ossos no vértice.
Além disso, a soma dos pesos dos 4 dados deve ser sempre igual a um.
A seguir, vamos ver como fica no shader.
Matriz matricial:
“bonesMatrices mat4 uniformes[kMaxBones];”
Informações sobre o efeito de 4 ossos em cada vértice:
“atributo vec2 bone0info;”
“atributo vec2 bone1info;”
“atributo vec2 bone2info;”
“atributo vec2 bone3info;”
vec2 – na coordenada X armazenamos o índice do osso (e convertemos para int no shader), na coordenada Y armazenamos o peso do impacto do osso no vértice. Por que você tem que transmitir esses dados em um vetor bidimensional? Porque o GLSL não suporta a passagem de estruturas legíveis em C com campos válidos para o shader.
A seguir darei um exemplo de obtenção das informações necessárias de um vetor para posterior substituição na fórmula animadoVertex:
“int bone0Index = int(bone0info.x);”
“float bone0weight = bone0info.y;”
“mat4 bone0matrix = boneMatrices[bone0Index];”
“int bone1Index = int(bone1info.x);”
“float bone1weight = bone1info.y;”
“mat4 bone1matrix = boneMatrices[bone1Index];”
“int bone2Index = int(bone2info.x);”
“float bone2weight = bone2info.y;”
“mat4 bone2matrix = boneMatrices[bone2Index];”
“int bone3Index = int(bone3info.x);”
“float bone3weight = bone3info.y;”
“mat4 bone3matrix = boneMatrices[bone3Index];”
Agora a estrutura de vértices preenchida na CPU deve ficar assim:
x, y, z, u, v, bone0index, bone0weight, bone1index, bone1weight, bone2index, bone2weight, bone3index, bone3weight
A estrutura do buffer de vértice é preenchida uma vez durante o carregamento do modelo, mas as matrizes de transformação são transferidas da CPU para o shader em cada quadro de renderização.
Nas partes restantes, descreverei o princípio de cálculo da animação na CPU, antes de transferi-la para o vertex shader, descreverei a árvore de nós ósseos, percorrendo a hierarquia de animação-modelo-nós-malha, matriz interpolação.
Fontes
http://ogldev.atspace.co. pt/www/tutorial38/tutorial38.html
Código fonte
https://gitlab.com/demensdeum/skeletal-animation