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

Posted

技术标签:

【中文标题】对于多个网格的 FBX 模型,网格未显示在正确位置【英文标题】:Mesh aren't displayed in their correct positions for a FBX model of multiple meshes 【发布时间】:2015-06-12 07:54:25 【问题描述】:

我导入了一个由多个网格组成的 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;

【问题讨论】:

感谢您的欢迎 :) 我的洗衣机的所有部件都放在不相关的地方。如果我不应用任何转换,那么它们中的大多数都处于正确的位置,但少数不是。不幸的是,我没有足够的声誉来上传图片。但我会给他们提供下拉框链接。 dl.dropboxusercontent.com/u/64007696/…dl.dropboxusercontent.com/u/64007696/… 注意,这个问题正在讨论on meta。 【参考方案1】:

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

你必须:

WorldMatrix= [ParentWorldMatrix * ModelMatrix] * GeometricMatrix

您只需要在之后乘以几何矩阵即可获得层次结构的世界。 “ParentMatrix”确实包含 GEOM。

所以模型应该是:

世界 = GrandGrandParentModel * [...] * GrandParentModel * ParentModel * 模型 * 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);

【讨论】:

让我们continue this discussion in chat。 我对代码不够熟悉;但是,GetMulplicationMatrix 似乎是一个错误(可能是 GetMultiplicationMatrix?) 哇 :D 你能相信我在 2 年内使用过这个错字,但我还没有看到吗?谢谢!【参考方案2】:

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

如果从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;

【讨论】:

好吧,这里的操作特别询问如何在没有sdk的情况下这样做 @diego.martinez 他有权在不接受/投票任何其他答案的情况下回答自己的问题。 @Omar:然而,在利用 Diego 的时间后第一次尝试删除问题后发布自己的答案使他(in4001)成为一个糟糕的演员。 @EthanFurman 如果 Diego 的回答有帮助/正确/完整,那么 OP 会在 10 个月前接受它。迭戈要求 15+,他得到了他要求的 50 倍。

以上是关于对于多个网格的 FBX 模型,网格未显示在正确位置的主要内容,如果未能解决你的问题,请参考以下文章

FBX 模型的面(某些)未正确渲染

Unity3D使用 FBX 格式的外部模型 ② ( FBX 模型与默认 3D 模型的区别 | FBX 模型贴图查找路径 | FBX 模型可设置多个材质 )

文档准备好后的数据源 ajax kendo 网格,因为模型未正确绑定在部分视图上

导入的 .fbx 模型是透明的

从 Blender 导出多个 .fbx 文件

在 Unity 中导入 Blender,如何生成正确的网格对撞机?