使用FBX SDK获取索引

3

我遇到了一个问题,不知道该使用什么来从FBX文件中获取索引。恢复数据是完全没有问题的(至少对于位置而言),但我似乎找不到如何获取索引的方法。

免责声明:很抱歉代码有点长,请随意编辑,如果您认为某些部分真的不必要。

我目前正在获取这样的数据:

// Recovering geometry
for (int meshIndex = 0; meshIndex < scene->GetGeometryCount(); ++meshIndex)
{
  const auto mesh = static_cast<FbxMesh*>(scene->GetGeometry(meshIndex));

  // Recovering positions
  int currentVertIndex = points_coords.size();
  points_coords.resize(currentVertIndex + mesh->GetControlPointsCount(), std::vector<coord_type>(3));

  for (int vertIndex = 0; vertIndex < mesh->GetControlPointsCount(); ++vertIndex, ++currentVertIndex)
  {
    const auto& vertPos = mesh->GetControlPointAt(vertIndex);

    points_coords[currentVertIndex][0] = vertPos[0]; // X position
    points_coords[currentVertIndex][1] = vertPos[1]; // Y position
    points_coords[currentVertIndex][2] = vertPos[2]; // Z position
  }

  // Iterate over normals with mesh->GetElementNormal()->GetDirectArray().GetCount()

  // Iterate over texcoords with mesh->GetElementUV()->GetDirectArray().GetCount()

关于索引,我正在迭代面(多边形)并按以下方式获取它们的顶点索引:

// Fetching positions' indices
int currentPosPolyIndex = face_indices.size();
face_indices.resize(currentPosPolyIndex + mesh->GetPolygonCount());

for (int polyIndex = 0; polyIndex < mesh->GetPolygonCount(); ++polyIndex, ++currentPosPolyIndex)
{
  const auto polySize = mesh->GetPolygonSize(polyIndex);
  face_indices[currentPosPolyIndex].resize(polySize);

  for (int polyVertIndex = 0; polyVertIndex < polySize; ++polyVertIndex)
    face_indices[currentPosPolyIndex][polyVertIndex] = mesh->GetPolygonVertex(polyIndex, polyVertIndex);
}

这样做对于只包含一个网格的FBX文件没问题,但是当有多个网格时,似乎无法将面缝合在一起。我会仔细调查是否是由于我使用的数据结构导致的问题,但如果有人发现了问题,请告诉我。
问题在于法线和纹理坐标的索引,我不知道如何获取它们。目前,我正在检查两者的映射模式,并尝试相应地填充数据:
  const auto texMapping = mesh->GetElementUV()->GetMappingMode();

  if (texMapping == FbxLayerElement::EMappingMode::eByControlPoint)
  {
    std::cout << "[FbxFileReader] Mapping mesh's texture coordinates by vertex." << std::endl;

    texture_face_indices.resize(texture_face_indices.size() + mesh->GetPolygonCount());

    std::copy(face_indices.cend() - mesh->GetPolygonCount(), face_indices.cend(), texture_face_indices.end() - mesh->GetPolygonCount());
  }
  else if (texMapping == FbxLayerElement::EMappingMode::eByEdge)
  {
    std::cout << "[FbxFileReader] Mapping mesh's texture coordinates by halfedge." << std::endl;
  }
  else if (texMapping == FbxLayerElement::EMappingMode::eByPolygon || texMapping == FbxLayerElement::EMappingMode::eByPolygonVertex)
  {
    std::cout << "[FbxFileReader] Mapping mesh's texture coordinates by face" << (texMapping == FbxLayerElement::EMappingMode::eByPolygonVertex ? " vertices" : "") << '.' << std::endl;

    int currentTexPolyIndex = texture_face_indices.size();
    texture_face_indices.resize(currentTexPolyIndex + mesh->GetPolygonCount());

    for (int polyIndex = 0; polyIndex < mesh->GetPolygonCount(); ++polyIndex, ++currentTexPolyIndex)
    {
      if (texMapping == FbxLayerElement::EMappingMode::eByPolygonVertex)
      {
        const auto polySize = mesh->GetPolygonSize(polyIndex);
        texture_face_indices[currentTexPolyIndex].resize(polySize);

        for (int polyVertIndex = 0; polyVertIndex < polySize; ++polyVertIndex)
          texture_face_indices[currentTexPolyIndex][polyVertIndex] = mesh->GetTextureUVIndex(polyIndex, polyVertIndex);
      }
      else
      {
        // Fetch face's texcoords & add it
        //texture_face_indices[currentTexPolyIndex].emplace_back(...);
      }
    }
  }
  else if (texMapping == FbxLayerElement::EMappingMode::eAllSame)
  {
    std::cout << "[FbxFileReader] Mapping mesh's texture coordinates by mesh." << std::endl;
  }
  else
  {
    std::cerr << "[FbxFileReader] Couldn't handle mesh's texture coordinates' mapping mode." << std::endl;
  }

目前我只处理面部[顶点]情况,对于纹理坐标,我认为它是正确的(当前无法获取材质,因此无法检查)。但是对于法线,我找不到有关获取其索引的任何信息。这就是为什么我只复制与位置相同的索引,我认为这是错误的:

  // Same checks for normals
  else if (normMapping == FbxLayerElement::EMappingMode::eByPolygon || normMapping == FbxLayerElement::EMappingMode::eByPolygonVertex)
  {
    std::cout << "[FbxFileReader] Mapping mesh's normals by face" << (normMapping == FbxLayerElement::EMappingMode::eByPolygonVertex ? " vertices" : "") << "." << std::endl;

    int currentNormPolyIndex = normal_face_indices.size();
    normal_face_indices.resize(currentNormPolyIndex + mesh->GetPolygonCount());

    for (int polyIndex = 0; polyIndex < mesh->GetPolygonCount(); ++polyIndex, ++currentNormPolyIndex)
    {
      if (normMapping == FbxLayerElement::EMappingMode::eByPolygonVertex)
      {
        const auto polySize = mesh->GetPolygonSize(polyIndex);
        normal_face_indices[currentNormPolyIndex].resize(polySize);

        for (int polyVertIndex = 0; polyVertIndex < polySize; ++polyVertIndex)
          normal_face_indices[currentNormPolyIndex][polyVertIndex] = face_indices[currentNormPolyIndex][polyVertIndex];
      }
      else { /*...*/ }
    }
  }

这是恢复索引的正确方法吗?我有什么遗漏吗?

1个回答

3
首先,您不应将所有网格数据放入同一个数组中。每个网格可以具有不同的材质,因此应使用单独的绘制调用进行绘制。但如果这不是您的选择,则错误在于以下行:
face_indices[currentPosPolyIndex][polyVertIndex] = mesh->GetPolygonVertex(polyIndex, polyVertIndex);

您需要将顶点放入一个单一的数组中,就像这样。
[(1-st mesh) V1, V2, V3, ..., (2-nd mesh) V52, V53, V54, ...]

但是 mesh->GetPolygonVertex(polyIndex, polyVertIndex) 返回的是相对于当前网格的索引,因此第二个网格将不会从 V52 开始,而是从 V1 开始。因此您需要计算一些偏移量。

int currentVertIndex = points_coords.size();
int meshVertIndexStart = currentVertIndex;
...
for (int polyVertIndex = 0; polyVertIndex < polySize; ++polyVertIndex)
    face_indices[currentPosPolyIndex][polyVertIndex] = meshVertIndexStart + mesh->GetPolygonVertex(polyIndex, polyVertIndex);

最好将顶点法线和UV纹理坐标放在同一个循环中获取索引。以下是一些代码:

FbxVector4 getNormal(FbxGeometryElementNormal* normalElement, int polyIndex, int posIndex) {
    if (normalElement->GetMappingMode() == FbxGeometryElement::eByControlPoint) {
        if (normalElement->GetReferenceMode() == FbxGeometryElement::eDirect)
            return normalElement->GetDirectArray().GetAt(posIndex);
        int i = normalElement->GetIndexArray().GetAt(posIndex);
        return normalElement->GetDirectArray().GetAt(i);
    }
    else if (normalElement->GetMappingMode() == FbxGeometryElement::eByPolygonVertex) {
        if (normalElement->GetReferenceMode() == FbxGeometryElement::eDirect)
            return normalElement->GetDirectArray().GetAt(polyIndex);
        int i = normalElement->GetIndexArray().GetAt(polyIndex);
        return normalElement->GetDirectArray().GetAt(i);
    }
    return FbxVector4();
}

FbxVector2 getUV(FbxGeometryElementUV* uvElement, int polyIndex, int posIndex) {
    if (uvElement->GetMappingMode() == FbxGeometryElement::eByControlPoint) {
        if (uvElement->GetReferenceMode() == FbxGeometryElement::eDirect)
            return uvElement->GetDirectArray().GetAt(posIndex);
        int i = uvElement->GetIndexArray().GetAt(posIndex);
        return uvElement->GetDirectArray().GetAt(i);
    }
    else if (uvElement->GetMappingMode() == FbxGeometryElement::eByPolygonVertex) {
        if (uvElement->GetReferenceMode() == FbxGeometryElement::eDirect)
            return uvElement->GetDirectArray().GetAt(polyIndex);
        int i = uvElement->GetIndexArray().GetAt(polyIndex);
        return uvElement->GetDirectArray().GetAt(i);
    }
    return FbxVector2();
}

...

int vertNum = 0;

for (int polyIndex = 0; polyIndex < mesh->GetPolygonCount(); ++polyIndex, ++currentPosPolyIndex) {
    const auto polySize = mesh->GetPolygonSize(polyIndex);
    face_indices[currentPosPolyIndex].resize(polySize);

    for (int polyVertIndex = 0; polyVertIndex < polySize; ++polyVertIndex) {
        int vertIndex = mesh->GetPolygonVertex(polyIndex, polyVertIndex);
        face_indices[currentPosPolyIndex][polyVertIndex] = meshVertIndexStart + vertIndex;

        FbxVector4 normal = getNormal(mesh->GetElementNormal(), vertNum, vertIndex);
        FbxVector2 uv = getUV(mesh->GetElementUV(), vertNum, vertIndex);
        vertNum++;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接