DISCLAIMER
This question has been completely rewritten to narrow the scope of the question in light of previous suggestions and answers, but the same problem still persists.
Currently I'm trying to implement skeletal animation (GPU skinning) in my project.
So far I have achieved single joint translation and rotation, and multi-jointed translation. The problem arises when I try to rotate a multi-jointed skeleton.
At the moment I'm following quite a few sources in trying to implement skeletal animation. The MD5 spec, a blog post with source code and I've also seen many other tutorials.
Currently when I try and load the popular "Bob Lamp" model, I get this result.
Some information about my implementation:
- My maths is ordered with "vector to the left"
- The vectors and rotations of animation frames are being converted into matrices
- I pre-multiply the inverse bind pose and pose matrices
Here is my shader code.
#version 330 core
smooth out vec2 vVaryingTexCoords;
smooth out vec3 vVaryingNormals;
smooth out vec4 vWeightColor;
uniform mat4 MV;
uniform mat4 MVP;
uniform mat4 Pallete[55];
layout(location = 0) in vec3 vPos;
layout(location = 1) in vec2 vTexCoords;
layout(location = 2) in vec3 vNormals;
layout(location = 3) in int vSkeleton[4];
layout(location = 4) in vec3 vWeight;
void main()
{
vec4 wpos2 = vec4(0.0);
vec4 norm2 = vec4(0.0);
vec4 wpos = vec4(vPos, 1.0);
vec4 norm = vec4(vNormals, 0.0);
vec4 weight = vec4(vWeight, (1.0f-(vWeight[0] + vWeight[1] + vWeight[2])));
mat4 BoneTransform = mat4(0.0);
for(int i = 0; i < 4; i++) {
float fW = weight[i];
if(fW > 0) {
int jI = vSkeleton[i];
vec4 tmpPos = wpos * (Pallete[jI]);
wpos2 += fW * tmpPos;
}
}
wpos2 /= wpos2.w;
vWeightColor = weight;
vVaryingTexCoords = vTexCoords;
vVaryingNormals = normalize(vec3(vec4(vNormals, 0.0) * MV));
gl_Position = wpos2 * MVP;
}
Another peculiar thing to mention is that multi-jointed animation works when the vertices are inline with the bones. As soon as the vertices move away from the bones, they deform incorrectly.
UPDATE
In response to @MickLH
My shader code now has wpos2 /= wpos2.w
after the for loop. This is the result.
BoneTransform += ...
should beBoneTransform *= ...
. \$\endgroup\$BoneTransform = (...) * BoneTransform;
\$\endgroup\$