对于多个网格的 FBX 模型,网格未显示在正确位置

Mesh aren't displayed in their correct positions for a FBX model of multiple meshes

我导入了一个由多个网格组成的 FBX 模型。不幸的是,我无法在正确的位置显示每个网格。对于每个网格,我将网格的几何变换与网格的局部变换相乘,然后将其传递给着色器。我该如何解决这个问题?

OpenGL 着色器

gl_Position = modelViewProjectionMatrix *TransformationMatrix*vertexPositionsOfMesh;

创建变换矩阵

GLKMatrix4 LcLTransformation = createTransformationMatrix(
   Mesh->LclRotation,
   Mesh->LclScaling,
   Mesh->LclTranslation);
GLKMatrix4 GeoTransformation = createTransformationMatrix(
   Mesh->GeometricRotation,
   Mesh->GeometricScaling,
   Mesh->GeometricTranslation);
TransformationMatrix=GLKMatrix4Transpose(GLKMatrix4Multiply(LcLTransformation,
                                                            GeoTransformation));

创建变换矩阵

GLKMatrix4 createTransformationMatrix(float* _rotation, float* _scaling, float* _translation)
{
  GLKMatrix4 Rx = GLKMatrix4Make(1, 0,                 0,                  0,
                                 0, cos(_rotation[0]), -sin(_rotation[0]), 0,
                                 0, sin(_rotation[0]), cos(_rotation[0]),  0,
                                 0, 0,                 0,                  1
                                 );

  GLKMatrix4 Ry = GLKMatrix4Make(cos(_rotation[1]),  0, sin(_rotation[1]), 0,
                                 0,                  1, 0,                 0,
                                 -sin(_rotation[1]), 0, cos(_rotation[1]), 0,
                                 0,                  0, 0,                 1
                                 );

  GLKMatrix4 Rz = GLKMatrix4Make(cos(_rotation[2]), -sin(_rotation[2]), 0, 0,
                                 sin(_rotation[2]), cos(_rotation[2]),  0, 0,
                                 0,                 0,                  1, 0,
                                 0,                 0,                  0, 1
                                 );

  GLKMatrix4 Translation = GLKMatrix4Make(1, 0, 0, _translation[0],
                                          0, 1, 0, _translation[1],
                                          0, 0, 1, _translation[2],
                                          0, 0, 0, 1
                                          );
  GLKMatrix4 Scaling = GLKMatrix4Identity;

  Scaling.m00 = _scaling[0];
  Scaling.m11 = _scaling[1];
  Scaling.m22 = _scaling[2];

  GLKMatrix4 Rotation = GLKMatrix4Multiply(GLKMatrix4Multiply(Rx, Ry), Rz);
  Transformation = GLKMatrix4Multiply(Scaling, GLKMatrix4Multiply(Rotation, Translation));
  return Transformation;
}

我在我的引擎中正确地从 MAX 导入了 fbx。

你必须:

WorldMatrix= [ParentWorldMatrix * ModelMatrix] * GeometricMatrix

您必须只乘以几何矩阵 获得层次结构的世界之后。 "ParentMatrix" 包含 GEOM。

所以模型应该是:

World = GrandGrandParentModel * [...] * GrandParentModel * ParentModel * Model * CurrentModelGeometric.

记住旋转是 ZYX。

代码:

void GRPNODE::UpdateWorldMatrix(bool * mustUpdate)
{
    if (!parent)
        return;

    parent->UpdateWorldMatrix(mustUpdate);

    if (worldmatrix_is_pending)
        *mustUpdate = true;

    if (*mustUpdate)
        this->worldmatrix.GetMulplicationMatrix(parent->GetWorldMatrixPointer(), &modelmatrix);
}

然后我得到节点的世界矩阵,当我变换顶点时,我做了:

void GRPELEMENT::ComputeMatrices(GRPMATRIX* viewmatrix, GRPMATRIX* viewprojection, GRPMATRIX* projection)
{
    modelmatrix=node->GetWorldMatrix();
    if (node->UsesGeometric)
        modelmatrix.GetMulplicationMatrix(modelmatrix, (*node->GetGeometricMatrix()));

    modelviewmatrix.GetMulplicationMatrix((*viewmatrix), modelmatrix);
    modelviewprojectionmatrix.GetMulplicationMatrix(projection, &modelviewmatrix);
}

void GRPNODE::MaxUpdate()
{
    // 1.0 Create Scale matrix
    scalematrix.BuildScaleMatrix(scale.vector[0], scale.vector[1], scale.vector[2]);

    // 1.1 Create current Rotation Translation Matrix
    Rx.BuildRotationMatrixX    (this->rotation.vector[0]);
    Ry.BuildRotationMatrixY    (this->rotation.vector[1]);
    Rz.BuildRotationMatrixZ    (this->rotation.vector[2]);

    if (UsesPreRotation)
    {
        Rpre.GetMulplicationMatrix(&prerotationmatrix, &Rz);
        Rt.GetMulplicationMatrix(&Rpre, &Ry);
        rotationmatrix.GetMulplicationMatrix(&Rt, &Rx);
    }
    else
    {
        Rt.GetMulplicationMatrix(&Rz, &Ry);
        rotationmatrix.GetMulplicationMatrix(&Rt, &Rx);
    }

    if (UsesPostRotation)
    {
        Rpost.GetMulplicationMatrix(&rotationmatrix, &postrotationmatrix);
        rotationmatrix = Rpost;
    }

    translationmatrix.BuildTranslationMatrix(position);

    //1.2. Create current model matrix (from stored matrix with rotation/translation)
    m.GetMulplicationMatrix(translationmatrix, rotationmatrix);
    modelmatrix.GetMulplicationMatrix(m, scalematrix);
}

根据Autodesk官方SDK中的the Transformations example code,节点在世界中的全局位置space是通过CalculateGlobalTransform(FbxNode* pNode)函数递归计算的,如下例代码所示。需要注意的非常重要的事情是,此函数不仅考虑了前旋转和 post 旋转,还考虑了枢轴位置和偏移量。 同样根据节点的转换继承类型,转换公式发生变化

如果从3ds Max导入模型,在计算出节点的全局变换信息后,仍然需要将其与几何变换相乘,才能找到节点属性在全局坐标中的位置。

/*
    Copyright (C) 2013 Autodesk, Inc.
    Terminology:
    Suffix "M" means this is a matrix, suffix "V" means it is a vector.
    T is translation.
    R is rotation.
    S is scaling.
    SH is shear.
    GlobalRM(x) means the Global Rotation Matrix of node "x".
    GlobalRM(P(x)) means the Global Rotation Matrix of the parent node of node "x".
    All other transforms are described in the similar way.

    The algorithm description:
    To calculate global transform of a node x according to different InheritType,
    we need to calculate GlobalTM(x) and [GlobalRM(x) * (GlobalSHM(x) * GlobalSM(x))] separately.
    GlobalM(x) = GlobalTM(x) * [GlobalRM(x) * (GlobalSHM(x) * GlobalSM(x))];

    InhereitType = RrSs:
    GlobalRM(x) * (GlobalSHM(x) * GlobalSM(x)) = GlobalRM(P(x)) * LocalRM(x) * [GlobalSHM(P(x)) * GlobalSM(P(x))] * LocalSM(x);

    InhereitType = RSrs:
    GlobalRM(x) * (GlobalSHM(x) * GlobalSM(x)) = GlobalRM(P(x)) * [GlobalSHM(P(x)) * GlobalSM(P(x))] * LocalRM(x) * LocalSM(x);

    InhereitType = Rrs:
    GlobalRM(x) * (GlobalSHM(x) * GlobalSM(x)) = GlobalRM(P(x)) * LocalRM(x) * LocalSM(x);

    LocalM(x)= TM(x) * RoffsetM(x)  * RpivotM(x) * RpreM(x) * RM(x) * RpostM(x) * RpivotM(x)^-1 * SoffsetM(x) *SpivotM(x) * SM(x) * SpivotM(x)^-1
    LocalTWithAllPivotAndOffsetInformationV(x) = Local(x).GetT();
    GlobalTV(x) = GlobalM(P(x)) * LocalTWithAllPivotAndOffsetInformationV(x);

    Notice: FBX SDK does not support shear yet, so all local transform won't have shear.
    However, global transform might bring in shear by combine the global transform of node in higher hierarchy.
    For example, if you scale the parent by a non-uniform scale and then rotate the child node, then a shear will
    be generated on the child node's global transform.
    In this case, we always compensates shear and store it in the scale matrix too according to following formula:
    Shear*Scaling = RotationMatrix.Inverse * TranslationMatrix.Inverse * WholeTranformMatrix
*/

FbxAMatrix CalculateGlobalTransform(FbxNode* pNode)
{
    FbxAMatrix lTranlationM, lScalingM, lScalingPivotM, lScalingOffsetM, lRotationOffsetM, lRotationPivotM, \
                lPreRotationM, lRotationM, lPostRotationM, lTransform;

    FbxAMatrix lParentGX, lGlobalT, lGlobalRS;

    if(!pNode)
    {
        lTransform.SetIdentity();
        return lTransform;
    }

    // Construct translation matrix
    FbxVector4 lTranslation = pNode->LclTranslation.Get();
    lTranlationM.SetT(lTranslation);

    // Construct rotation matrices
    FbxVector4 lRotation = pNode->LclRotation.Get();
    FbxVector4 lPreRotation = pNode->PreRotation.Get();
    FbxVector4 lPostRotation = pNode->PostRotation.Get();
    lRotationM.SetR(lRotation);
    lPreRotationM.SetR(lPreRotation);
    lPostRotationM.SetR(lPostRotation);

    // Construct scaling matrix
    FbxVector4 lScaling = pNode->LclScaling.Get();
    lScalingM.SetS(lScaling);

    // Construct offset and pivot matrices
    FbxVector4 lScalingOffset = pNode->ScalingOffset.Get();
    FbxVector4 lScalingPivot = pNode->ScalingPivot.Get();
    FbxVector4 lRotationOffset = pNode->RotationOffset.Get();
    FbxVector4 lRotationPivot = pNode->RotationPivot.Get();
    lScalingOffsetM.SetT(lScalingOffset);
    lScalingPivotM.SetT(lScalingPivot);
    lRotationOffsetM.SetT(lRotationOffset);
    lRotationPivotM.SetT(lRotationPivot);

    // Calculate the global transform matrix of the parent node
    FbxNode* lParentNode = pNode->GetParent();
    if(lParentNode)
    {
        lParentGX = CalculateGlobalTransform(lParentNode);
    }
    else
    {
        lParentGX.SetIdentity();
    }

    //Construct Global Rotation
    FbxAMatrix lLRM, lParentGRM;
    FbxVector4 lParentGR = lParentGX.GetR();
    lParentGRM.SetR(lParentGR);
    lLRM = lPreRotationM * lRotationM * lPostRotationM;

    //Construct Global Shear*Scaling
    //FBX SDK does not support shear, to patch this, we use:
    //Shear*Scaling = RotationMatrix.Inverse * TranslationMatrix.Inverse * WholeTranformMatrix
    FbxAMatrix lLSM, lParentGSM, lParentGRSM, lParentTM;
    FbxVector4 lParentGT = lParentGX.GetT();
    lParentTM.SetT(lParentGT);
    lParentGRSM = lParentTM.Inverse() * lParentGX;
    lParentGSM = lParentGRM.Inverse() * lParentGRSM;
    lLSM = lScalingM;

    //Do not consider translation now
    FbxTransform::EInheritType lInheritType = pNode->InheritType.Get();
    if(lInheritType == FbxTransform::eInheritRrSs)
    {
        lGlobalRS = lParentGRM * lLRM * lParentGSM * lLSM;
    }
    else if(lInheritType == FbxTransform::eInheritRSrs)
    {
        lGlobalRS = lParentGRM * lParentGSM * lLRM * lLSM;
    }
    else if(lInheritType == FbxTransform::eInheritRrs)
    {
        FbxAMatrix lParentLSM;
        FbxVector4 lParentLS = lParentNode->LclScaling.Get();
        lParentLSM.SetS(lParentLS);

        FbxAMatrix lParentGSM_noLocal = lParentGSM * lParentLSM.Inverse();
        lGlobalRS = lParentGRM * lLRM * lParentGSM_noLocal * lLSM;
    }
    else
    {
        FBXSDK_printf("error, unknown inherit type! \n");
    }

    // Construct translation matrix
    // Calculate the local transform matrix
    lTransform = lTranlationM * lRotationOffsetM * lRotationPivotM * lPreRotationM * lRotationM * lPostRotationM * lRotationPivotM.Inverse()\
                 * lScalingOffsetM * lScalingPivotM * lScalingM * lScalingPivotM.Inverse();
    FbxVector4 lLocalTWithAllPivotAndOffsetInfo = lTransform.GetT();
    // Calculate global translation vector according to:
    // GlobalTranslation = ParentGlobalTransform * LocalTranslationWithPivotAndOffsetInfo
    FbxVector4 lGlobalTranslation = lParentGX.MultT(lLocalTWithAllPivotAndOffsetInfo);
    lGlobalT.SetT(lGlobalTranslation);

    //Construct the whole global transform
    lTransform = lGlobalT * lGlobalRS;

    return lTransform;
}