2
votes

I have implemented a skeletal animation system where I seem to be missing one last detail for it to work properly.

I have made an animation which only a part of the character has bones. In this image The stickman has a waving arm, but the arm waves at the wrong place compared to the rest of the stickman. (You barely see it between his legs)

Animated stickman

I will try to outline the basics of my matrix computation to see if I am doing something wrong.

Computation of bone specific absolute and relative animation matrix (based on my keyframe matrix data):

        if (b == this->root) {
                b->absoluteMatrix = M;
            } else {
                b->absoluteMatrix = b->parent->absoluteMatrix * M;
            } 

            b->skinningMatrix = b->absoluteMatrix * inverse(b->offsetMatrix);       

            if (this->currentAnimationTime == 0) {
                cout << "Bone '" << b->name << "' skinningMatrix:\n";
                printMatrix(b->skinningMatrix);

                cout << "Bone '" << b->name << "' absoluteMatrix:\n";
                printMatrix(b->absoluteMatrix);

                cout << "Bone '" << b->name << "' offsetMatrix:\n";
                printMatrix(b->offsetMatrix);

                cout << "---------------------------------\n";
            }

skinningMatrix which I send to the GPU. This prints the following:

output from debugging

where offsetMatrix is a transform that transforms from mesh space to bone space in bind pose.

In my shader I then do:

layout(location = 0) in vec4 v; // normal vertex data
newVertex = (skinningMatrix[boneIndex.x] * v) * weights.x;
newVertex = (skinningMatrix[boneIndex.y] * v) * weights.y + newVertex;
newVertex = (skinningMatrix[boneIndex.z] * v) * weights.z + newVertex;

Any hints on what could be wrong with my computations?

1
The bits you posted look fine to me. Could you go into a little more detail on how you compute offsetMatrix? Have you verified that skinningMatrix is the identity matrix when your character is in bind pose? Sum of the weights is always 1? Does it work if you only use one bone per vertex?Andreas Haferburg
The animation of the arm works properly. The arm itself is just in the wrong place. The offsetMatrix is grabbed for each bone from the ASSIMP import which is documented to be:"offsetMatrix is a transform that transforms from mesh space to bone space in bind pose". I convert it from aiMatrix4x4 to glm::mat4. I am looking at my skinningmatrix at time = 0, and it is not the identity matrix. If I want to compute the bindpose matrix myself I would just grab absoluteMatrix at time 0? Or initialization?toeplitz
I added some debugging output to the post if it can help.toeplitz

1 Answers

0
votes

I am currently working through skeletal animation myself, and the only thing I noticed which may be an issue is with how you use the offset matrix from ASSIMP. The matrix in question is a matrix which "transforms from mesh space to bone space in bind pose".

To my knowledge this matrix is intended to be used 'as-is', which will essentially take your vertices into the bones local space, which you will than multiply by a 'new' global joint pose which will take the vertices from bone space to model space.

When you inverse the matrix, you are transforming the vertices into model space again, and than with your current animation frames global joint pose, pushing the vertices even further.

I believe your solution will be to remove the inverting of your offset matrix, which will result in your vertices moving from 'model-joint-model'.