Сетки не отображаются в правильных положениях для модели FBX с несколькими сетками

Я импортировал модель FBX, которая состоит из нескольких сеток. К сожалению, я не могу отобразить каждую сетку в правильном положении. Для каждой сетки я умножаю геометрическое преобразование сетки на локальное преобразование сетки и затем передаю ее в шейдер. Как я могу исправить эту проблему?

OpenGL Shader

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

createTransformation Matrix

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

2 ответа

Решение

В соответствии с примером кода Transformations в официальном SDK Autodesk, глобальная позиция узла в мировом пространстве рекурсивно вычисляется с помощью функции 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;
}

Я правильно импортировал fbx из MAX в моем движке.

Ты должен:

WorldMatrix= [ParentWorldMatrix * ModelMatrix] * GeometricMatrix

Вы должны ТОЛЬКО умножать геометрические матрицы ПОСЛЕ получения миров иерархии. "ParentMatrix" НЕ содержит ГЕОМ.

Итак, модель должна быть:

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);
}
Другие вопросы по тегам