Skip to content

Commit 88cc0e7

Browse files
cdtwiggfacebook-github-bot
authored andcommitted
Populate polygon face fields in FBX I/O
Summary: Wire up the polyFaces, polyFaceSizes, and polyTexcoordFaces fields added in the previous diff so they are populated during FBX load and written during FBX save. Load: copy raw polygon topology from PolygonData into the new mesh fields alongside the existing triangulation. Save: when polygon data is available, write actual polygons (quads, n-gons) instead of only triangles; fall back to triangulated faces otherwise. Differential Revision: D94577295
1 parent b8049ba commit 88cc0e7

File tree

2 files changed

+74
-16
lines changed

2 files changed

+74
-16
lines changed

momentum/io/fbx/fbx_io.cpp

Lines changed: 53 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,56 @@ void addMetaData(::fbxsdk::FbxNode* skeletonRootNode, const Character& character
561561
}
562562
}
563563

564+
void writePolygonsToFbxMesh(const Mesh& mesh, ::fbxsdk::FbxMesh* lMesh) {
565+
if (!mesh.polyFaces.empty() && !mesh.polyFaceSizes.empty()) {
566+
// Write original polygon topology
567+
uint32_t offset = 0;
568+
for (const auto polySize : mesh.polyFaceSizes) {
569+
lMesh->BeginPolygon();
570+
for (uint32_t i = 0; i < polySize; ++i) {
571+
lMesh->AddPolygon(mesh.polyFaces[offset + i]);
572+
}
573+
lMesh->EndPolygon();
574+
offset += polySize;
575+
}
576+
} else {
577+
// Fall back to triangulated faces
578+
for (const auto& face : mesh.faces) {
579+
lMesh->BeginPolygon();
580+
for (int i = 0; i < 3; i++) {
581+
lMesh->AddPolygon(face[i]);
582+
}
583+
lMesh->EndPolygon();
584+
}
585+
}
586+
}
587+
588+
void writeTextureUVIndicesToFbxMesh(
589+
const Mesh& mesh,
590+
::fbxsdk::FbxMesh* lMesh,
591+
fbxsdk::FbxLayerElement::EType uvType) {
592+
if (!mesh.polyFaces.empty() && !mesh.polyFaceSizes.empty()) {
593+
uint32_t offset = 0;
594+
int polyIdx = 0;
595+
for (const auto polySize : mesh.polyFaceSizes) {
596+
for (uint32_t i = 0; i < polySize; ++i) {
597+
const uint32_t texIdx = mesh.polyTexcoordFaces.empty() ? mesh.polyFaces[offset + i]
598+
: mesh.polyTexcoordFaces[offset + i];
599+
lMesh->SetTextureUVIndex(polyIdx, i, texIdx, uvType);
600+
}
601+
offset += polySize;
602+
polyIdx++;
603+
}
604+
} else {
605+
for (int faceIdx = 0; faceIdx < static_cast<int>(mesh.texcoord_faces.size()); ++faceIdx) {
606+
const auto& texcoords = mesh.texcoord_faces[faceIdx];
607+
lMesh->SetTextureUVIndex(faceIdx, 0, texcoords[0], uvType);
608+
lMesh->SetTextureUVIndex(faceIdx, 1, texcoords[1], uvType);
609+
lMesh->SetTextureUVIndex(faceIdx, 2, texcoords[2], uvType);
610+
}
611+
}
612+
}
613+
564614
void saveFbxCommon(
565615
const filesystem::path& filename,
566616
const Character& character,
@@ -687,7 +737,6 @@ void saveFbxCommon(
687737
if (saveMesh && character.mesh != nullptr) {
688738
// Add the mesh
689739
const int numVertices = character.mesh.get()->vertices.size();
690-
const int numFaces = character.mesh.get()->faces.size();
691740
::fbxsdk::FbxNode* meshNode = ::fbxsdk::FbxNode::Create(scene, "body_mesh");
692741
::fbxsdk::FbxMesh* lMesh = ::fbxsdk::FbxMesh::Create(scene, "mesh");
693742
lMesh->SetControlPointCount(numVertices);
@@ -704,14 +753,7 @@ void saveFbxCommon(
704753
lMesh->SetControlPointAt(point, normal, i);
705754
}
706755
// Add polygons to lMesh
707-
for (int iFace = 0; iFace < numFaces; iFace++) {
708-
lMesh->BeginPolygon();
709-
for (int i = 0; i < 3; i++) { // We have tris for models. This could be extended for
710-
// supporting Quads or npoly if needed.
711-
lMesh->AddPolygon(character.mesh.get()->faces[iFace][i]);
712-
}
713-
lMesh->EndPolygon();
714-
}
756+
writePolygonsToFbxMesh(*character.mesh, lMesh);
715757
lMesh->BuildMeshEdgeArray();
716758
meshNode->SetNodeAttribute(lMesh);
717759

@@ -733,13 +775,8 @@ void saveFbxCommon(
733775
lMesh->AddTextureUV(::fbxsdk::FbxVector2(texcoords[0], 1.0f - texcoords[1]), uvType);
734776
}
735777

736-
// Set UV indices for each face. We only have triangles.
737-
int faceCount = 0;
738-
for (const auto& texcoords : character.mesh->texcoord_faces) {
739-
lMesh->SetTextureUVIndex(faceCount, 0, texcoords[0], uvType);
740-
lMesh->SetTextureUVIndex(faceCount, 1, texcoords[1], uvType);
741-
lMesh->SetTextureUVIndex(faceCount++, 2, texcoords[2], uvType);
742-
}
778+
// Set UV indices for each face.
779+
writeTextureUVIndicesToFbxMesh(*character.mesh, lMesh, uvType);
743780
}
744781

745782
// ---------------------------------------------

momentum/io/fbx/openfbx_loader.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,24 @@ parseSkeleton(const ofbx::Object* sceneRoot, const std::string& skelRoot, Permis
501501
return {skeleton, jointFbxNodes, locators, collision};
502502
}
503503

504+
void populatePolyFaceData(
505+
Mesh& mesh,
506+
const PolygonData& vertices,
507+
size_t vertexOffset,
508+
size_t textureCoordOffset) {
509+
for (const auto& idx : vertices.indices) {
510+
mesh.polyFaces.push_back(idx + static_cast<uint32_t>(vertexOffset));
511+
}
512+
for (size_t i = 0; i + 1 < vertices.offsets.size(); ++i) {
513+
mesh.polyFaceSizes.push_back(vertices.offsets[i + 1] - vertices.offsets[i]);
514+
}
515+
if (!vertices.textureIndices.empty()) {
516+
for (const auto& idx : vertices.textureIndices) {
517+
mesh.polyTexcoordFaces.push_back(idx + static_cast<uint32_t>(textureCoordOffset));
518+
}
519+
}
520+
}
521+
504522
void parseSkinnedModel(
505523
const ofbx::Mesh* meshRoot,
506524
const std::vector<const ofbx::Object*>& boneFbxNodes,
@@ -659,6 +677,9 @@ void parseSkinnedModel(
659677
mesh.texcoord_faces.emplace_back(t + Eigen::Vector3i::Constant(textureCoordOffset));
660678
}
661679

680+
// Populate polygon face data (preserves original topology)
681+
populatePolyFaceData(mesh, vertices, vertexOffset, textureCoordOffset);
682+
662683
const auto* blendshapes = geometry->getBlendShape();
663684
if (loadBlendShapes == LoadBlendShapes::Yes && blendshapes) {
664685
if (!blendShape) {

0 commit comments

Comments
 (0)