-8

I have imported an FBX model that composes of multiple meshes. Unfortunately, I am not able to display each mesh in their correct positions. For each mesh I multiply a geometric transformation of the mesh with a local transformation of the mesh and then pass it to shader. How can I fix this problem?

OpenGL Shader

gl_Position = modelViewProjectionMatrix *TransformationMatrix*vertexPositionsOfMesh;

Creating Transformation Matrix

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

createTransformationMatrix

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;
}
jophab
  • 5,356
  • 14
  • 41
  • 60
in4001
  • 656
  • 6
  • 24
  • Thank you for the welcome :) All the parts of my washing machine positioned in irrelevant places. If I dont apply any transformation then most of them are in correct position but a few are not. Unfortunately I dont have enough reputation to upload pictures. but I will give drop box link to them. https://dl.dropboxusercontent.com/u/64007696/11088246_10152942960933743_622205299_n.jpg https://dl.dropboxusercontent.com/u/64007696/11124403_10152950018173743_1588711748_n.jpg – in4001 Apr 07 '15 at 17:26
  • 2
    Note, this question is being discussed [on meta](http://meta.stackoverflow.com/questions/317470/what-can-i-do-if-a-user-removes-a-question-after-ive-written-an-extended-answer). – Tim Post Feb 24 '16 at 06:01

2 Answers2

143

I correctly imported fbx from MAX in my engine.

You have to:

WorldMatrix= [ParentWorldMatrix * ModelMatrix] * GeometricMatrix

You have to ONLY multiply geometric matrices AFTER getting the worlds of the hierarchy. The "ParentMatrix" does NOT contain GEOMs.

So a model should be:

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

Remember that the rotations are ZYX.

Code:

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

And after that I get the world matrix of the node, when I transform vertices I do:

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);
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
diego.martinez
  • 1,051
  • 2
  • 11
  • 25
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/104187/discussion-between-in4001-and-diego-martinez). – in4001 Feb 22 '16 at 15:22
  • 4
    I'm not familiar enough with the code; however, `GetMulplicationMatrix` seems like an error (possibly meant to be `GetMultiplicationMatrix`?) – Tas Feb 24 '16 at 01:12
  • 1
    wow :D can you believe I have uses that typo during 2 years, and I haven't seen it yet? thank you! – diego.martinez Feb 24 '16 at 08:39
-29

According to the Transformations example code in Autodesk's official SDK, a node's global position in the world space is recursively calculated by the CalculateGlobalTransform(FbxNode* pNode) function as in the sample code below. Very important things to notice are this function takes into account not just pre and post rotations, but also pivot location and offsets. Also depending on the node's transformation inheritance type, the transformation formula changes.

In case you import the model from 3ds Max, after calculating a node's global transformation information, you still have to multiply it with geometric transformations in order to find the position of node attribute in global coordinates.

/*
    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;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
in4001
  • 656
  • 6
  • 24
  • 1
    well, the op here specifically asked how to do so without the sdk – diego.martinez Feb 24 '16 at 08:42
  • 9
    @diego.martinez he has the right to answer his own question without accepting/voting any other answer. – Omar Feb 24 '16 at 11:01
  • 4
    @Omar: Nevertheless, posting his own answer after first trying to delete the question after taking advantange of Diego's time makes him (in4001) a bad actor. – Ethan Furman Feb 24 '16 at 20:13
  • 3
    @EthanFurman if Diego's answer was helpful/correct/complete, the OP would have accepted it 10 months before. Diego asked for 15+, he got 50 times what he has asked for. – Omar Feb 24 '16 at 20:19