first of all i would like to say that i read everything out there and still did not figure it out quite yet.

In my project i need to implement a skinning technique, but before going there i need to get the standar Linear Blend Skinning working.

I'm using assimp to load my model. For testing purposes my model is a cylindre with a single mesh and 2 bones. There are no animations, the goal of my demo is to manually move the bones.

I read every tutorial/article outhere about assimp and skeletal animation. So i think i got the loading part right. I got the mTransformation from the nodes and got the offsetMatrix from the meshes with the same name (i used a map to store the bones/names).

i did some printing to verify my structure and i'm loading the correct info, i'm getting identity matrices everywhere (wich i think is normal since there is no animation and it's just a simple mesh).

The part i could not figure out still , is how i apply these transformations to my vertices. This point affects the loading too ,when i apply a scale/translation on a mesh in blender i can't get it in my renderer.

in my bones i store 2 matrices and i have a third one that represents the final transformation. I did not understand how i would compute this one, i saw some people using and inverse of the root transform and i have a hard time coding something i don't understand.

struct Weights
{
    uint vertexID;
    float weight;
};

struct Bone
{
    Bone():parent(nullptr){}
    ~Bone()
    {
        for(auto p: children)
                delete p;
    }


    std::string name; // bone name

    QMatrix4x4 nodeTransform; //Transformation of the node
    QMatrix4x4 offsetMatrix;    // Going into the bone's space
    QMatrix4x4 finalTransfrom; // where we store the final transfrom

    QVector<Weights> boneWeights; // bone wheights


    Bone *parent; // pointer to the parent node nullptr if root
    QVector<Bone*> children; // storing pointers to the children
};

thank you for help !

  • Posting this as comment because I'm not sure if I understand you right. But when you want to know in which order you have to calculate the matrixes of parent bones to get the final matix this tutorial might help you tutorial. If it was helpful I can post it as an answer. – Skalli Mar 17 '16 at 15:59

I'm just starting to piece this together myself, but I've managed to apply transformations to bones by exporting them as collada files. Nothing else works AFAIK. This does not work for me with fbx.

Here is the "formula" as I understand it:

bone_transform = inverse(mRootNode->mTransformation) * aiBoneNode->parent->mTransformation * animation->RST matrix * aiBone->mOffsetMatrix; 

gl_Position = MVP * bone_transform * vertex;

I'll try and elaborate, minus all of the code I used to traverse aiScene... First, you need to get the offset matrix from the bone:

scene->mMeshes[1]->mBones[idx]->mOffsetMatrix)

Next, look up the transform matrices:

parentTransform(transform, scene->mAnimations[idx]->mChannels[cIdx]->mNodeName);
inline void parentTransform(glm::mat4 &result, aiNode* node) {
  if (node->mParent != 0x0) {
    glm::mat4 tmp = aiMatrix4x4ToGlm(&node->mParent->mTransformation);
    result = tmp  * result;
    parentTransform(result, node->mParent);
  }
}

Then, get the keyframe transformation:

                            glm::quat key_rotate(
                                scene->mAnimations[idx]->mChannels[cIdx]->mRotationKeys[0].mValue.w,
                                scene->mAnimations[idx]->mChannels[cIdx]->mRotationKeys[0].mValue.x,
                                scene->mAnimations[idx]->mChannels[cIdx]->mRotationKeys[0].mValue.y,
                                scene->mAnimations[idx]->mChannels[cIdx]->mRotationKeys[0].mValue.z
                            );

                            glm::mat4 key_translate = glm::translate(
                                glm::mat4(1.0f), 
                                glm::vec3(
                                    scene->mAnimations[idx]->mChannels[cIdx]->mPositionKeys[0].mValue.x,
                                    scene->mAnimations[idx]->mChannels[cIdx]->mPositionKeys[0].mValue.y,
                                    scene->mAnimations[idx]->mChannels[cIdx]->mPositionKeys[0].mValue.z
                                )
                            );

Next, mash it all together:

                                m_scenes[mIdx]->m_bones[bIdx].keyframe_transformation = 

                                glm::inverse(aiMatrix4x4ToGlm(&scene->mRootNode->mTransformation)) * 
                                //aiMatrix4x4ToGlm(&scene->mRootNode->mTransformation) * 
                                transform * 
                                //aiMatrix4x4ToGlm(&scene->mRootNode->mChildren[0]->mTransformation) *
                                key_translate *
                                glm::mat4_cast(key_rotate) *
                                m_scenes[mIdx]->m_bones[bIdx].offsetMatrix;

Send it to your vertex shader:

gl_Position = proj_matrix * mv_matrix * bones[boneId] * vec4(position, 1.0);

And voilà.

  • hi i just noticed your answer i'll get into it and get back to you ASAP thanks :) ! – Bob Maza Dec 21 '16 at 13:25

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.