2016-02-06 179 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的後,所有轉換都是正確的。