2015-05-11 5 views
1

У меня была эта очень неприятная проблема в прошлые выходные. Я должен иметь возможность читать в триангулированном файле FBX 2014, который содержит сетку, экспортированную из Maya, и читать ее вершины и индексы, которые должны быть переданы в рендеринг (DirectX) для вызова DrawIndexed.Как правильно читать индексы FBX 2014 для DirectX?

Так как у меня есть это установка, что есть TUniqueVertex структура

struct TUniqueVertex 
{ 
    XMFLOAT3 m_vPosition, // Vertex positions 
    XMFLOAT3 m_vNormal,  // Vertex normals 
    XMFLOAT2 m_UVs   // Vertex UVs 
    int m_nControlPointIndex, // Control Point Index 
} 

Этот код здесь, загрузит в FbxMesh в CMesh класса. Которая содержит вершины и индексы сетки.

class CMesh 
{ 
    ... 
    vector<TUniqueVertex> m_vVertices; 
    vector<unsigned int> m_vIndices; 
} 

код для загрузки в CMesh:

bool LoadMesh(FbxMesh* pMesh, CMesh cMesh) 
{ 
    int polygonCount = pMesh->GetPolygonCount();   
    FbxVector4* controlPoints = pMesh->GetControlPoints(); 
    int controlPointCount = pMesh->GetControlPointsCount(); 

    int vertexID = 0; 

    for (int polygon = 0; polygon < polygonCount; polygon++) 
    { 
     int polyVertCount = pMesh->GetPolygonSize(polygon); 

    for (int polyVert = 0; polyVert < polyVertCount; polyVert++) 
    { 
     CMesh::TUniqueVertex uniqueVert; 

     int cpIndex = pMesh->GetPolygonVertex(polygon, polyVert); 

     // Grab our CP index as well our position information 
     uniqueVert.m_nControlPointIndex = cpIndex; 
     uniqueVert.m_vPosition = 
     XMFLOAT3((float)controlPoints[cpIndex].mData[0], 
       (float)controlPoints[cpIndex].mData[1], 
       (float)controlPoints[cpIndex].mData[2]); 

     // Grab UVs 
     int uvElementCount = pMesh->GetElementUVCount(); 

     for (int uvElement = 0; uvElement < uvElementCount; uvElement++) 
     { 
      FbxGeometryElementUV* geomElementUV = pMesh>GetElementUV(uvElement); 

      FbxLayerElement::EMappingMode mapMode = geomElementUV->GetMappingMode(); 
      FbxLayerElement::EReferenceMode refMode = geomElementUV->GetReferenceMode(); 

      int directIndex = -1; 

      if (FbxGeometryElement::eByControlPoint == mapMode) 
      { 
       if (FbxGeometryElement::eDirect == refMode) 
       { 
        directIndex = cpIndex; 
       } 
       else if (FbxGeometryElement::eIndexToDirect == refMode) 
       { 
        directIndex = geomElementUV->GetIndexArray().GetAt(cpIndex); 
       } 
      } 
      else if (FbxGeometryElement::eByPolygonVertex == mapMode) 
      { 
       if (FbxGeometryElement::eDirect == refMode || FbxGeometryElement::eIndexToDirect == refMode) 
       { 
        directIndex = pMesh->GetTextureUVIndex(polygon, polyVert); 
       } 

      } 

      // If we got a UV index 
      if (directIndex != -1) 
      { 
       FbxVector2 uv = geomElementUV->GetDirectArray().GetAt(directIndex); 

       uniqueVert.m_UVs = XMFLOAT2((float)uv.mData[0], 
              (float)uv.mData[1]); 
      } 
     } 

     // Grab normals 
     int normElementCount = pMesh->GetElementNormalCount(); 

     for (int normElement = 0; normElement < normElementCount; normElement++) 
     { 
      FbxGeometryElementNormal* geomElementNormal = pMesh->GetElementNormal(normElement); 

      FbxLayerElement::EMappingMode mapMode = geomElementNormal->GetMappingMode(); 
      FbxLayerElement::EReferenceMode refMode = geomElementNormal->GetReferenceMode(); 

      int directIndex = -1; 

      if (FbxGeometryElement::eByPolygonVertex == mapMode) 
      { 
       if (FbxGeometryElement::eDirect == refMode) 
       { 
        directIndex = vertexID; 
       } 
       else if (FbxGeometryElement::eIndexToDirect == refMode) 
       { 
        directIndex = geomElementNormal->GetIndexArray().GetAt(vertexID); 
       } 
      } 

      // If we got an index 
      if (directIndex != 1) 
      { 
       FbxVector4 norm = geomElementNormal->GetDirectArray().GetAt(directIndex); 

       uniqueVert.m_vNormal = XMFLOAT3((float)norm.mData[0], 
               (float)norm.mData[1], 
               (float)norm.mData[2]); 

      } 
     } 

     // Unique Vertices stuff 
     vector<CMesh::TUniqueVertex>& uniqueVerts = cMesh.GetVertices(); 

     size_t size = uniqueVerts.size(); 
     size_t i; 

     for (i = 0; i < size; i++) 
     { 
      if (uniqueVert == uniqueVerts[i]) 
      { 
       break; 
      } 
     } 

     if (i == size) 
     { 
      uniqueVerts.push_back(uniqueVert); 
     } 

     cMesh.GetIndices().push_back(i); 
     ++vertexID; 
    } 
} 

return true; 
} 

Выполнение этого метода нагрузок в вершинах, нормалей и UVs правильно. Тем не менее, при загрузке в индексах и прохождения cMesh.GetIndices() рассчитывать на DrawIndexed вызова, индексы полностью непригодной и выглядит в графическом отладчике:

Graphic Debugger

Incase никому интересно, индексы выглядят следующим образом:

012, 023, 456, 657, 891, 081, 011, 121, 314, 121, 415, 161, 718, 171, 918, 202, 122, 212, 023

И вот тест .fbx, который я пытаюсь загрузить информацию:

Cube.fbx direct download

Если кто-то может помочь мне с этим, я был бы очень благодарен, так как это проблема вызвала у меня столько стресса: D

ответ

1

Вы используете левые координаты просмотра или право- (см. link)? Если вы используете левые координаты просмотра, вам нужно перевернуть обмотку каждого треугольника в индексном буфере.

assert((indices.size() % 3) == 0); 
    for(auto it = indices.begin(); it != indices.end(); it += 3) 
    { 
     std::swap(*it, *(it+2)); 
    } 

Вам также может понадобиться перевернуть координаты текстуры, а также:

for(auto it = vertices.begin(); it != vertices.end(); ++it) 
    { 
     it->textureCoordinate.x = (1.f - it->textureCoordinate.x); 
    } 

Исторически наиболее DirectX приложения используют левые координаты просмотра. XNA Game Studio и большинство приложений OpenGL используют правые координаты просмотра.

BTW, поэтому оба -fliptriangles+ и -invertvtexcoord+ включены по умолчанию в Samples Content Exporter для SDKMESH.