user923
user923

Reputation: 559

Translating and rotating child meshes by their local rotation and position (as in Unity)

I am exporting models that use an old method of animation. Every bone in the skeletal mesh has a translation and rotation value which are local. In Unity, I can set the local position of each submesh and the model looks correct at every frame.

I am now trying to export these meshes from my C# program using glmsharp and am getting strange visual exports. I use the model export code elsewhere and it works so we will assume the issue is in the translation and rotation of the submesh vertices.

This is my approach:

public void ShiftSkeletonValues(List<SkeletonNode> skeleton, List<BoneTrack> boneTracks,
    mat4 parentMatrix, int index, int frame, ILogger logger)
{
    mat4 translationMatrix = mat4.Translate(boneTracks[index]._frames[frame].Translation);
    mat4 rotationMatrix = glm.ToMat4(boneTracks[index]._frames[frame].Rotation);

    mat4 modelMatrix = translationMatrix * rotationMatrix;
    mat4 combinedMatrix = modelMatrix * parentMatrix;

    ShiftAndRotateVertices(combinedMatrix, index, logger);

    foreach (var pieces in skeleton[index].Children)
    {
        ShiftSkeletonValues(skeleton, boneTracks, combinedMatrix, pieces, frame, logger);
    }
}

This function iterates the skeleton recursively. When invoking this method, I pass in an identity mat4. This function figures out the translation matrix and then the rotation matrix (Rotation is a quaternion). I then combine them into the model matrix, combine it again with the parent matrix and then shift and rotate vertices in each submesh. Then for any connected pieces (children), I recursively call this function with the combine matrix.

The code I use to actual modify the vertex values is pretty straightforward:

private void ShiftAndRotateVertices(mat4 combineModelMatrix, int index, ILogger logger)
{
    MobVertexPiece mobPiece = MobPieces[index];

    for (int i = 0; i < mobPiece.Count; ++i)
    {
        var position = Vertices[mobPiece.Start + i];
        vec4 newPosition = new vec4(position, 1.0f);
        vec4 shiftedPosition = combineModelMatrix * newPosition;
        Vertices[mobPiece.Start + i] = shiftedPosition.xyz;
    }
}

I convert the vertex to a vec4, and multiply it by the combined model matrix. Again, this logic should mimic the way Unity handles local rotations. Not sure where I went wrong. I think it has something to do with the rotation matrix.

Upvotes: 1

Views: 516

Answers (1)

user923
user923

Reputation: 559

Played around a bit more with it and realized I had everything right except the final operation. It should have been parentMatrix * modelMatrix when combining them. Andrea also suggested this in a comment. Thank you!

Upvotes: 1

Related Questions