Hi, over the past week, I have been struggling alot with 3D vertex skinning. I use blender to create my model, to rig them and I expert the mesh and its armature in COLLADA file (.dae). Btw, I am using java with lwjgl, wich uses mostly opengl.
However, I am having trouble trying to get my mesh into its bind pose in my game engine.
Here is what I have :
In the <library_visual_scenes> node of the collada file, I can read the whole bone hierarchy, and get the local matrix of each joint:
<node id="Bone" name="Bone" sid="Bone" type="JOINT">
<matrix sid="transform">1 0 0 0 0 7.54979e-8 -1 0 0 1 7.54979e-8 0 0 0 0 1</matrix>
Then, in the <library_controllers> node, I firstly read the bind shape matrix:
<bind_shape_matrix>1 -2.22045e-16 0 2.32831e-10 0 1 1.19249e-8 1.19249e-8 0 -1.19249e-8 0.9999999 0.9999999 0 0 0 1
In the same node, I also read all the inverse bind matrix aswell as all the weights associated to vertex.
I have verified all the datas after loading them to see if they get loaded correctly, so the problem should not be in loading datas, unless there is something I don't know about collada matrices.
After loading the collada file, I calculate the world matrices of each joint by multiplying its local matrix with its aprent's world matrix. For the root joint, the local matrix becomes the world matrix.
The vertex shader is where I calculate the final vertex position. Here is how I proceed (For some reason I cannot post code anymore) :
vec4 actualPosition = vec4(position, 1.0);
vec4 weightedPos = (((actualPosition * bindShapeMatrix) * boneTransforms[boneIDs.x]) * boneWeights.x) +
(((actualPosition * bindShapeMatrix) * boneTransforms[boneIDs.y]) * boneWeights.y) +
(((actualPosition * bindShapeMatrix) * boneTransforms[boneIDs.z]) * boneWeights.z) +
(((actualPosition * bindShapeMatrix) * boneTransforms[boneIDs.w]) * boneWeights.w);
actualPosition += weightedPos;
The bindShapeMatrix was taken from the collada file. It's the same for every vertex.
The boneIDs are indices to get the skinningMatrix from boneTransfroms
The boneWeights are weights that the corresponding boneID affect the current vetex. (total of 1.0, for all 4)
The boneTransforms array contains all the joints skinning matrices(I think thats how they call it)
To get the skinning matrix of a joint, I multiply its inverse bind matric with its world matrix :
Matrix4f skinningMatrix = new Matrix4f();
Matrix4f.mul(invBindShapeMatrix, worldMatrix, skinningMatrix);
But sadly, this doesnt give me the right results. On the left you can see an image of what it should look like in its bind pose, taken from blender. On the right, there is 2 images of different views of what it actually look like in my game engine,
As you can see, it is pretty close but something is definetly wrong.
For testing purpose, I have break it down to a simple cube with 2 bones. Bottom bone being the root bone, affecting the bottom 4 vertices of the cube, and the top bone affecting the other 4 top vertices. And I get the same results, some vertices (not all) are not at their position.
From this example, I definitely think something is wrong with the root bone, or something is wrong with the weights, because vertices affected by the top bones (4 top vetices) are in their correct position.
I am currently trying on paper to do all the matrix muliplications by myself to see if I get the same results. After doing the calculations in the shader, the vertex position should not change, so I am trying to see whats wrong. The down part of glsl is that I cannot put breakpoints or print stuff in the console to debug, so it makes things harder.