WebGL / GPU Skinning / Skeletal Animation

2.6k Views Asked by At

I am frustratingly close to working skeletal animation in WebGL.

Background

I have a model with a zombie walk animation that I got for free. I downloaded the entire thing in a single Collada file. I wrote a parser to get all the vertices, normals, joints influence indices/weights, and joint matrices. I am able to render the character in its bind pose by doing

joints[i].skinning_matrix = MatrixMultiply(joints[i].inverse_bind_pose_matrix, joints[i].world_matrix);

where a joint's world matrix is the joint's bind_pose_matrix multiplied by its parent's world matrix. I got the inverse_bind_pose_matrix by doing:

joints[i].inverse_bind_pose_matrix = MatrixInvert(joints[i].world_matrix);

So really, rendering the character in its bind pose is just passing Identity matrices to the shader, so maybe I'm not even doing that part right at all. However, the inverse bind pose matrices that I calculate are nearly identical to the ones supplied by the Collada file, so I'm pretty sure those are good.

Here's my model in its bind pose:

bind pose

Problem

Once I go ahead and try to calculate the skinning matrix using a single frame of the animation (I chose frame 10 at random), it still resembles a man but something is definitely wrong.

I'm using the same inverse_bind_pose_matrix that I calculated in the first place. I'm using a new world matrix, calculated instead by multiplying each joint's keyframe/animation matrix by its parent's new world matrix.

I'm not doing any transposing anywhere in my entire codebase, though I think I've tried transposing pretty much any combination of matrices to no avail.

Here is my model in his animation frame 10 pose:

anim pose

Some Relevant Code

vertex shader:

attribute float aBoneIndex1;
// up to aBoneIndex5

attribute float aBoneWeight1;
// up to aBoneWeight5

uniform mat4 uBoneMatrices[52];

void main(void) {
  vec4 vertex = vec4(0.0, 0.0, 0.0, 0.0);
  vertex += aBoneWeight1 * vec4(uBoneMatrices[int(aBoneIndex1)] * aPosition);
  vertex += aBoneWeight2 * vec4(uBoneMatrices[int(aBoneIndex2)] * aPosition);
  vertex += aBoneWeight3 * vec4(uBoneMatrices[int(aBoneIndex3)] * aPosition);
  vertex += aBoneWeight4 * vec4(uBoneMatrices[int(aBoneIndex4)] * aPosition);
  vertex += aBoneWeight5 * vec4(uBoneMatrices[int(aBoneIndex5)] * aPosition);

  // normal/lighting part

  // the "/ 90.0" simply scales the model down, problem persists without it.
  gl_Position = uPMatrix * uMVMatrix * vec4(vertex.xyz / 90.0, 1.0);
}

You can see my parser in its entirety (if you really really want to...) on GitHub and you can see the model live here.

0

There are 0 best solutions below