Home > front end >  Assimp animation data gives unexpected values
Assimp animation data gives unexpected values

Time:09-05

I'm using Assimp to load in animation data from an fbx file, but when I load the fbx with Blender and compare the keyframe values between Blender and the values Assimp provides, they're not the same.

According to the Blender animation curve

However, Assimp returns the following keyframe values for the same animation channel:

Time:  0  Value: 2.34362
Time:  1  Value: 2.04054
Time:  2  Value: 1.73746
Time:  3  Value: 1.43438
Time:  4  Value: 1.13131
Time:  5  Value: 0.828227
Time:  6  Value: 0.525148
Time:  7  Value: 0.22207
Time:  8  Value: -0.0225141
Time:  9  Value: -0.267098
Time: 10  Value: -0.511682
Time: 11  Value: -0.756265
Time: 12  Value: -1.00085
Time: 13  Value: -1.24543
Time: 14  Value: -1.49002
Time: 15  Value: -1.7346
Time: 16  Value: -1.72213
...
Time: 30  Value: 2.34362

When I investigate further, these values that Assimp returns appear to be mapped to the model space, as can be seen here. Blender model space position

This discovery seemed to bring me one step closer to correcting the animation data as I should only need to transform the animation data from model space to bone space. Fortunately Assimp provides a mOffsetMatrix property on each bone which is documented as

Matrix that transforms from bone space to mesh space in bind pose. This matrix describes the position of the mesh in the local space of this bone when the skeleton was bound.

According to this, mOffsetMatrix seems to be the inverse of what I want, so I should only need to transform the animation data by the inverse of this matrix. On the contrary, transforming by the inverse matrix continues to give me invalid data, however to my surprise transforming the animation data by mOffsetMatrix as is (and not inverted) gives me the correct values:

Time:  0  Value: -2.12155
Time:  1  Value: -1.81847
Time:  2  Value: -1.51539
Time:  3  Value: -1.21231
Time:  4  Value: -0.909236
Time:  5  Value: -0.606157
Time:  6  Value: -0.303079
Time:  7  Value: 0
Time:  8  Value: 0.244584
Time:  9  Value: 0.489167
Time: 10  Value: 0.733751
Time: 11  Value: 0.978335
Time: 12  Value: 1.22292
Time: 13  Value: 1.4675
Time: 14  Value: 1.71209
Time: 15  Value: 1.95667
Time: 16  Value: 1.9442
...
Time: 30  Value: -2.12155

This appeared to be my answer, but of course that'd be too easy. This transformation gives me the correct animation values only for animations applied to root bones. Animation data for child bones are completely incorrect and I cannot for the life of me figure out what space that animation data is in. I've tried all sorts of combinations of combining the matrices from the parent nodes create a matrix to transform the animation data into bone space, but none of the data appears remotely correct. Even when comparing the animation values that Assimp returns against the model-space values as I did with the root bones, the values are not correct, implying the animation data that Assimpt returns is neither in bone space nor model space.

The documentation of Assimp seems incorrect on both counts of what space the animation data is in and what mOffsetMatrix represents unless I'm completely misunderstanding what it's saying. But here is the puzzle: In what space is Assimp's animation data, and how do I transform it to bone-space?

CodePudding user response:

The animation system of the Asset-Importer-Lib uses offset-matrixes based on the root node from the asset. So all information are based on the local model-space from your imported mode.

I am not sure why the animation data for the children are incorrect. I have opened a ticket for this issue (see Children-bone transformation is broken).

CodePudding user response:

The documentation is half correct. All animation data is relative to the parent bone/node, but the mOffsetMatrix property on aiBone objects holds the transformation from mesh space to bone space (as opposed to bone space to mesh space as the documentation indicates).

To transform the animation data from the parent bone's space to the local bone's space, the data should be transformed from the parent's bone space to mesh space, then from mesh space to the current bone's space. This can be done by finding the parent bone and creating a compound matrix, i.e. aiMatrix4x4 parentBoneToChildBone(bone.mOffsetMatrix * aiMatrix4x4(parentBone.mOffsetMatrix).Inverse()); then use this matrix to transform the animation data. (Note .Inverse() modifies the original matrix so a copy should be made before inverting.)

If the bone in question does not have a parent bone, then you can simply transform the animation data by bone.mOffsetMatrix. Since the parent of a root bone should be the armature (which probably is also in the same space as the mesh), and the animation data is relative to the bone's parent (which in this case should be the armature/mesh space), we can use mOffsetMatrix to transform the animation data directly into the bone space.

const aiMatrix4x4& modelToBone(bone.mOffsetMatrix); // Renamed for clarity...
aiMatrix4x4 parentToBone;
const auto parentBoneI = bonesByName.find(bone.mNode->mParent->mName.C_Str());
if (parentBoneI != bonesByName.cend())
{
    aiMatrix4x4 parentToModel(parentBoneI->second->mOffsetMatrix);
    parentToModel.Inverse();
    parentToBone = modelToBone * parentToModel;
}
else
{
    parentToBone = modelToBone;
}

// ...

// Convert position data from parent's bone space to the current bone's space...
const aiVectorKey& positionKey = channel.mPositionKeys[keyIndex];
const aiVector3D position(parentToBone * positionKey.mValue);

// Convert rotation data into bone space...
const aiQuatKey& rotationKey = channel.mRotationKeys[keyIndex];
const aiQuaternion rotation(aiQuaternion(aiMatrix3x3(parentToBone)) * rotationKey.mValue);

  • Related