首页 > 解决方案 > 通过局部旋转和位置平移和旋转子网格(如在 Unity 中)

问题描述

我正在导出使用旧动画方法的模型。骨架网格物体中的每个骨骼都有一个局部的平移和旋转值。在 Unity 中,我可以设置每个子网格的本地位置,并且模型在每一帧看起来都是正确的。

我现在正在尝试使用 glmsharp 从我的 C# 程序中导出这些网格,并且得到了奇怪的视觉导出。我在其他地方使用模型导出代码,它可以工作,所以我们假设问题出在子网格顶点的平移和旋转中。

这是我的方法:

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);
    }
}

这个函数递归地迭代骨架。调用此方法时,我传入了一个标识 mat4。该函数计算出平移矩阵,然后计算出旋转矩阵(Rotation 是一个四元数)。然后我将它们组合到模型矩阵中,再次将其与父矩阵组合,然后在每个子网格中移动和旋转顶点。然后对于任何连接的部分(孩子),我用组合矩阵递归地调用这个函数。

我用来实际修改顶点值的代码非常简单:

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;
    }
}

我将顶点转换为 vec4,并将其乘以组合模型矩阵。同样,这个逻辑应该模仿 Unity 处理局部旋转的方式。不知道我哪里出错了。我认为这与旋转矩阵有关。

标签: c#unity3dopenglglm-math

解决方案


多玩了一会儿,意识到除了最后的操作,我什么都做对了。parentMatrix * modelMatrix结合它们时应该是这样。安德里亚也在评论中提出了这一点。谢谢!


推荐阅读