Assimp and Skinning transforms

Started by
1 comment, last by KaiserJohan 7 years, 8 months ago

Trying to wrap my head around skinning transforms for skeletal animations. Using assimp to parse model data and GLM as math library (right-handed)

Here's how I understand it, the order in which transforms are done:


// calculate translation/rotation/scaling (TRS) of each bone and concatenate it with its parent
foreach bone in boneList
    MAT4_bone = calculate TRS-matrix based on time
    MAT4_parent = get parent TRS-matrix of bone
    MAT4_bone = MAT4_parent * MAT4_bone
    
// after, apply bone offset and inverse root matrix
// why is the inverse root matrix needed anyway?
MAT4_rootInvMatrix = the inverse of the root matrix of the scene
foreach bone in boneList
    MAT4_bone = the (now) absolute TRS matrix of a bone
    MAT4_offset = the bones offset matrix given by assimp
    MAT4_final = MAT4_rootInvMatrix * MAT4_bone * MAT4_offset

As far as I can tell, each assimp nodes original mTransform is just discard and not used at all?

And in code:


void AnimationUpdater::Update(const Milliseconds elapsedTime)
{
    for (AnimationInstance& animationInstance : mActiveAnimations)
    {
        const BoneIndex bonesBegin = animationInstance.mBoneRange.first;
        const BoneIndex bonesEnd = animationInstance.mBoneRange.second;

        // mBoneTransforms - the final skinning transforms
        
        // root has no parent
        // note: root is always front
        Mat4& rootTransform = mBoneTransforms.at(bonesBegin);
        rootTransform = animation.InterpolateBoneTransform(bonesBegin, elapsedTime);

        // interpolate bone animations
        // parens always appear before their children
        const uint32_t numBones = bonesEnd - bonesBegin;
        for (uint32_t boneOffset = 1; boneOffset < numBones; ++boneOffset)
        {
            const BoneIndex bone = bonesBegin + boneOffset;
            const BoneIndex parentBone = animation.GetParentIndex(bone);
            const Mat4& parentTransform = mBoneTransforms.at(parentBone);

            Mat4& transform = mBoneTransforms.at(bone);
            transform = parentTransform * animation.InterpolateBoneTransform(bone, elapsedTime);
        }

        const Mat4& rootInverseTransform = animation.GetInverseRootMatrix();
        for (uint32_t boneOffset = 1; boneOffset < numBones; ++boneOffset)
        {
            const BoneIndex bone = bonesBegin + boneOffset;
            const Mat4& boneOffsetTransform = animation.GetBoneOffsetTransform(bone);

            Mat4& transform = mBoneTransforms.at(bone);
            transform = rootInverseTransform * transform * boneOffsetTransform;
        }
    }
}

Yet it all looks like a tangled mess during rendering. Is there anything obvious I'm missing here?

Advertisement

There's a lot of things that can go wrong. Start with the basics like is the mesh scaled and rotated the same as the armature at identity and are the bone heads where you expect them to be?

Alright, I've pretty much solved it I believe, just a few finishing touches.

If it helps anyone, I re-arranged assimps bone hierarchy into a custom parent-before-child container and forgot to map assimp bone indices to these (re-arranged) bone indices and thus the vertices picked the wrong bone transforms in the shader.

As a starter, try replacing all the bone transforms with identity matrices and make sure it renders correctly.

Also try a tool like assimps modelviewer (http://www.open3mod.com/) to inspect the node/bone hierarchy and compare it to yours.

This topic is closed to new replies.

Advertisement