2016-02-06 84 views
1

最近,试图用FBX sdk导入一个用3dmax制作的3d模型,我几乎立即遇到了转换问题。一个非常简单的网格(由两个节点组成的球体分成两部分)无论如何都有一个节点偏移。我尝试了几个(非常含糊的)计算转换最新SDK文档的方法......但结果是一样的。我会提供代码和网格以防任何人都可以指出任何错误。FBX节点转换计算

辅助函数:

FbxAMatrix MeshManager::GetGlobalPosition(FbxNode* pNode, const FbxTime& pTime, FbxPose* pPose, FbxAMatrix* pParentGlobalPosition) 
{ 
    FbxAMatrix lGlobalPosition; 
    bool  lPositionFound = false; 

    if (pPose) 
    { 
     int lNodeIndex = pPose->Find(pNode); 

     if (lNodeIndex > -1) 
     { 
      // The bind pose is always a global matrix. 
      // If we have a rest pose, we need to check if it is 
      // stored in global or local space. 
      if (pPose->IsBindPose() || !pPose->IsLocalMatrix(lNodeIndex)) 
      { 
       lGlobalPosition = GetPoseMatrix(pPose, lNodeIndex); 
      } 
      else 
      { 
       // We have a local matrix, we need to convert it to 
       // a global space matrix. 
       FbxAMatrix lParentGlobalPosition; 

       if (pParentGlobalPosition) 
       { 
        lParentGlobalPosition = *pParentGlobalPosition; 
       } 
       else 
       { 
        if (pNode->GetParent()) 
        { 
         lParentGlobalPosition = GetGlobalPosition(pNode->GetParent(), pTime, pPose); 
        } 
       } 

       FbxAMatrix lLocalPosition = GetPoseMatrix(pPose, lNodeIndex); 
       lGlobalPosition = lParentGlobalPosition * lLocalPosition; 
      } 

      lPositionFound = true; 
     } 
    } 

    if (!lPositionFound) 
    { 
     // There is no pose entry for that node, get the current global position instead. 

     // Ideally this would use parent global position and local position to compute the global position. 
     // Unfortunately the equation 
     // lGlobalPosition = pParentGlobalPosition * lLocalPosition 
     // does not hold when inheritance type is other than "Parent" (RSrs). 
     // To compute the parent rotation and scaling is tricky in the RrSs and Rrs cases. 
     lGlobalPosition = pNode->EvaluateGlobalTransform(pTime); 
    } 

    return lGlobalPosition; 
} 

// Get the matrix of the given pose 
FbxAMatrix MeshManager::GetPoseMatrix(FbxPose* pPose, int pNodeIndex) 
{ 
    FbxAMatrix lPoseMatrix; 
    FbxMatrix lMatrix = pPose->GetMatrix(pNodeIndex); 

    memcpy((double*)lPoseMatrix, (double*)lMatrix, sizeof(lMatrix.mData)); 

    return lPoseMatrix; 
} 

// Get the geometry offset to a node. It is never inherited by the children. 
FbxAMatrix MeshManager::GetGeometry(FbxNode* pNode) 
{ 
    const FbxVector4 lT = pNode->GetGeometricTranslation(FbxNode::eSourcePivot); 
    const FbxVector4 lR = pNode->GetGeometricRotation(FbxNode::eSourcePivot); 
    const FbxVector4 lS = pNode->GetGeometricScaling(FbxNode::eSourcePivot); 

    return FbxAMatrix(lT, lR, lS); 
} 

mat4 FbxMatToGlm(const FbxAMatrix& mat) { 
    dvec4 c0 = glm::make_vec4((double*)mat.GetColumn(0).Buffer()); 
    dvec4 c1 = glm::make_vec4((double*)mat.GetColumn(1).Buffer()); 
    dvec4 c2 = glm::make_vec4((double*)mat.GetColumn(2).Buffer()); 
    dvec4 c3 = glm::make_vec4((double*)mat.GetColumn(3).Buffer()); 
    glm::mat4 convertMatr = mat4(c0, c1, c2, c3); 
    return inverse(convertMatr); 
} 

网格提取:

void MeshManager::extractMeshRecursive(FbxScene* mScene, FbxNode* pNode, FbxAMatrix& pParentGlobalPosition, shared_ptr<Mesh> mesh, unsigned &currentNode) { 
    // Find out what type of node this is 
    FbxNodeAttribute* lNodeAttribute = pNode->GetNodeAttribute(); 

    FbxAMatrix lGlobalPosition = GetGlobalPosition(pNode, 1, mScene->GetPose(-1) , &pParentGlobalPosition); 
    FbxAMatrix lGeometryOffset = GetGeometry(pNode); 
    FbxAMatrix lGlobalOffsetPosition = lGlobalPosition * lGeometryOffset; 

    if (lNodeAttribute) 
    { 
     // Get the actual node mesh data if it is a mesh this time 
     // (You could use this like the sample where they draw other nodes like cameras) 
     if (lNodeAttribute->GetAttributeType() == FbxNodeAttribute::eMesh) 
     { 
      // Draw the actual mesh data 
      FbxMesh* lMesh = pNode->GetMesh(); 

      if (lMesh->IsTriangleMesh() == false) { 
       FbxGeometryConverter conv(mFbxManager); 
       conv.Triangulate(lNodeAttribute, true); 
      } 

      const uint lVertexCount = lMesh->GetControlPointsCount(); 
      const uint lTriangleCount = lMesh->GetPolygonCount(); 

      // May not have any vertex data 
      if (lVertexCount == 0) return; 

      mesh->nodes.push_back(MeshNode()); 

      FbxVector4* pControlPoints = lMesh->GetControlPoints(); 
      for (uint i = 0; i < lVertexCount; i++) 
      { 
       mesh->nodes[currentNode].vertices.push_back(vec3((float)pControlPoints[i].mData[0], (float)pControlPoints[i].mData[1], (float)pControlPoints[i].mData[2])); 
      } 

      mesh->nodes[currentNode].localTransform = FbxMatToGlm(lGlobalOffsetPosition); 
     } 
     currentNode++; 
    } 
... Extracting other vertex attributes and materials ... 

// Now check if this node has any children attached 
    const int lChildCount = pNode->GetChildCount(); 
    for (int lChildIndex = 0; lChildIndex < lChildCount; ++lChildIndex) 
    { 
     // Draw this child 
     extractMeshRecursive(mScene, pNode->GetChild(lChildIndex), lGlobalPosition, mesh, currentNode); 
    } 
} 

我得到的结果看起来是这样的:enter image description here 作为反对:enter image description here

A Mesh

回答

2

不正确的部分在这里:

mat4 FbxMatToGlm(const FbxAMatrix& mat) { 
    dvec4 c0 = glm::make_vec4((double*)mat.GetColumn(0).Buffer()); 
    dvec4 c1 = glm::make_vec4((double*)mat.GetColumn(1).Buffer()); 
    dvec4 c2 = glm::make_vec4((double*)mat.GetColumn(2).Buffer()); 
    dvec4 c3 = glm::make_vec4((double*)mat.GetColumn(3).Buffer()); 
    glm::mat4 convertMatr = mat4(c0, c1, c2, c3); 
    return inverse(convertMatr); // <--- Incorrect 
} 

没有必要对得到的矩阵求逆。应该是改为。我最初做的是,但未经调整的网格比例非常巨大,我无法在渲染器中看到它,我开始修补它。在3D Studio的FBX导出窗口中将毫米作为Unit的后,所有转换都是正确的。