Skip to content

Commit ffc1f2a

Browse files
cdtwiggmeta-codesync[bot]
authored andcommitted
Handle polygon fields in mesh subset operations (#1068)
Summary: Pull Request resolved: #1068 reduceMeshInternal (used by reduceMeshByFaces, reduceMeshByVertices, and reduceMeshComponents) didn't handle the polyFaces/polyFaceSizes/polyTexcoordFaces fields. After a mesh subset operation, the polygon data would be stale. Add remapPolyFaces helper to filter and remap polygon data during mesh reduction, using the same active-vertex logic as triangulated faces. Also add verticesToPolys, polysToVertices conversion functions and reduceMeshByPolys for selecting mesh subsets by polygon. Reviewed By: fbogo Differential Revision: D94579400
1 parent aa8babf commit ffc1f2a

File tree

5 files changed

+577
-5
lines changed

5 files changed

+577
-5
lines changed

cmake/build_variables.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ character_test_sources = [
222222
"test/character/linear_skinning_test.cpp",
223223
"test/character/locator_test.cpp",
224224
"test/character/locator_state_test.cpp",
225+
"test/character/mesh_reduction_test.cpp",
225226
"test/character/parameter_limits_test.cpp",
226227
"test/character/parameter_transform_test.cpp",
227228
"test/character/pose_shape_test.cpp",

momentum/character/character_utility.cpp

Lines changed: 191 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,53 @@ std::vector<Eigen::Vector3i> remapFaces(
845845
return remappedFaces;
846846
}
847847

848+
template <typename T>
849+
void remapPolyFaces(
850+
MeshT<T>& newMesh,
851+
const MeshT<T>& mesh,
852+
const std::vector<bool>& activeVertices,
853+
const std::vector<size_t>& reverseVertexMapping,
854+
const std::vector<size_t>& reverseTexcoordMapping) {
855+
if (mesh.polyFaces.empty()) {
856+
return;
857+
}
858+
859+
newMesh.polyFaceSizes.reserve(mesh.polyFaceSizes.size());
860+
newMesh.polyFaces.reserve(mesh.polyFaces.size());
861+
if (!mesh.polyTexcoordFaces.empty()) {
862+
newMesh.polyTexcoordFaces.reserve(mesh.polyTexcoordFaces.size());
863+
}
864+
865+
uint32_t offset = 0;
866+
for (const auto polySize : mesh.polyFaceSizes) {
867+
// Check if all vertices of this polygon are active
868+
bool allActive = true;
869+
for (uint32_t i = 0; i < polySize; ++i) {
870+
const auto vtx = mesh.polyFaces[offset + i];
871+
if (vtx >= activeVertices.size() || !activeVertices[vtx]) {
872+
allActive = false;
873+
break;
874+
}
875+
}
876+
877+
if (allActive) {
878+
newMesh.polyFaceSizes.push_back(polySize);
879+
for (uint32_t i = 0; i < polySize; ++i) {
880+
newMesh.polyFaces.push_back(
881+
static_cast<uint32_t>(reverseVertexMapping[mesh.polyFaces[offset + i]]));
882+
}
883+
if (!mesh.polyTexcoordFaces.empty()) {
884+
for (uint32_t i = 0; i < polySize; ++i) {
885+
newMesh.polyTexcoordFaces.push_back(
886+
static_cast<uint32_t>(reverseTexcoordMapping[mesh.polyTexcoordFaces[offset + i]]));
887+
}
888+
}
889+
}
890+
891+
offset += polySize;
892+
}
893+
}
894+
848895
std::vector<std::vector<int32_t>> remapLines(
849896
const std::vector<std::vector<int32_t>>& lines,
850897
const std::vector<size_t>& mapping) {
@@ -923,6 +970,57 @@ std::vector<bool> facesToVertices(
923970
return activeVertices;
924971
}
925972

973+
std::vector<bool> verticesToPolys(
974+
const std::vector<uint32_t>& polyFaces,
975+
const std::vector<uint32_t>& polyFaceSizes,
976+
const std::vector<bool>& activeVertices) {
977+
if (polyFaceSizes.empty()) {
978+
return {};
979+
}
980+
MT_CHECK(!polyFaceSizes.empty());
981+
std::vector<bool> activePolys(polyFaceSizes.size(), false);
982+
uint32_t offset = 0;
983+
for (size_t polyIdx = 0; polyIdx < polyFaceSizes.size(); ++polyIdx) {
984+
const auto polySize = polyFaceSizes[polyIdx];
985+
bool allActive = true;
986+
for (uint32_t i = 0; i < polySize; ++i) {
987+
const auto vtx = polyFaces[offset + i];
988+
if (vtx >= activeVertices.size() || !activeVertices[vtx]) {
989+
allActive = false;
990+
break;
991+
}
992+
}
993+
activePolys[polyIdx] = allActive;
994+
offset += polySize;
995+
}
996+
return activePolys;
997+
}
998+
999+
std::vector<bool> polysToVertices(
1000+
const std::vector<uint32_t>& polyFaces,
1001+
const std::vector<uint32_t>& polyFaceSizes,
1002+
const std::vector<bool>& activePolys,
1003+
size_t vertexCount) {
1004+
std::vector<bool> activeVertices(vertexCount, false);
1005+
if (activePolys.empty()) {
1006+
return activeVertices;
1007+
}
1008+
uint32_t offset = 0;
1009+
for (size_t polyIdx = 0; polyIdx < polyFaceSizes.size(); ++polyIdx) {
1010+
const auto polySize = polyFaceSizes[polyIdx];
1011+
if (activePolys[polyIdx]) {
1012+
for (uint32_t i = 0; i < polySize; ++i) {
1013+
const auto vtx = polyFaces[offset + i];
1014+
if (vtx < vertexCount) {
1015+
activeVertices[vtx] = true;
1016+
}
1017+
}
1018+
}
1019+
offset += polySize;
1020+
}
1021+
return activeVertices;
1022+
}
1023+
9261024
// Internal mesh reduction function used by both reduceMeshComponents and
9271025
// the public reduceMeshByFaces/reduceMeshByVertices for Mesh.
9281026
template <typename T>
@@ -954,22 +1052,26 @@ MeshT<T> reduceMeshInternal(
9541052
newMesh.lines = remapLines(mesh.lines, reverseVertexMapping);
9551053
}
9561054

1055+
std::vector<size_t> reverseTextureVertexMapping;
9571056
if (!mesh.texcoord_faces.empty() && !mesh.texcoords.empty()) {
9581057
std::vector<bool> activeTextureTriangles = activeFaces;
9591058
activeTextureTriangles.resize(mesh.texcoord_faces.size(), false);
9601059

9611060
const std::vector<bool> activeTextureVertices =
9621061
facesToVertices(mesh.texcoord_faces, activeTextureTriangles, mesh.texcoords.size());
9631062

964-
auto [forwardTextureVertexMapping, reverseTextureVertexMapping] =
965-
createIndexMapping(activeTextureVertices);
1063+
auto [forwardTextureVertexMapping, revTexMapping] = createIndexMapping(activeTextureVertices);
1064+
reverseTextureVertexMapping = std::move(revTexMapping);
9661065

9671066
newMesh.texcoords = selectVertices(mesh.texcoords, forwardTextureVertexMapping);
9681067
newMesh.texcoord_faces =
9691068
remapFaces(mesh.texcoord_faces, reverseTextureVertexMapping, activeTextureTriangles);
9701069
newMesh.texcoord_lines = remapLines(mesh.texcoord_lines, reverseTextureVertexMapping);
9711070
}
9721071

1072+
// Remap polygon face data
1073+
remapPolyFaces(newMesh, mesh, activeVertices, reverseVertexMapping, reverseTextureVertexMapping);
1074+
9731075
return newMesh;
9741076
}
9751077

@@ -1185,6 +1287,61 @@ std::vector<bool> facesToVertices(const MeshT<T>& mesh, const std::vector<bool>&
11851287
return facesToVertices(mesh.faces, activeFaces, mesh.vertices.size());
11861288
}
11871289

1290+
template <typename T>
1291+
std::vector<bool> verticesToPolys(const MeshT<T>& mesh, const std::vector<bool>& activeVertices) {
1292+
MT_CHECK(
1293+
activeVertices.size() == mesh.vertices.size(),
1294+
"Active vertices size ({}) does not match mesh vertex count ({})",
1295+
activeVertices.size(),
1296+
mesh.vertices.size());
1297+
1298+
return verticesToPolys(mesh.polyFaces, mesh.polyFaceSizes, activeVertices);
1299+
}
1300+
1301+
template <typename T>
1302+
std::vector<bool> polysToVertices(const MeshT<T>& mesh, const std::vector<bool>& activePolys) {
1303+
MT_CHECK(
1304+
activePolys.size() == mesh.polyFaceSizes.size(),
1305+
"Active polys size ({}) does not match polygon count ({})",
1306+
activePolys.size(),
1307+
mesh.polyFaceSizes.size());
1308+
1309+
return polysToVertices(mesh.polyFaces, mesh.polyFaceSizes, activePolys, mesh.vertices.size());
1310+
}
1311+
1312+
template <typename T>
1313+
MeshT<T> reduceMeshByPolys(const MeshT<T>& mesh, const std::vector<bool>& activePolys) {
1314+
MT_CHECK(
1315+
activePolys.size() == mesh.polyFaceSizes.size(),
1316+
"Active polys size ({}) does not match polygon count ({})",
1317+
activePolys.size(),
1318+
mesh.polyFaceSizes.size());
1319+
1320+
// Convert polygon selection to vertex selection, then to face selection
1321+
const auto activeVertices = polysToVertices(mesh, activePolys);
1322+
const auto activeFaces = verticesToFaces(mesh, activeVertices);
1323+
1324+
return reduceMeshInternal(mesh, activeVertices, activeFaces);
1325+
}
1326+
1327+
template <typename T>
1328+
CharacterT<T> reduceMeshByPolys(
1329+
const CharacterT<T>& character,
1330+
const std::vector<bool>& activePolys) {
1331+
MT_CHECK(character.mesh, "Cannot reduce mesh: character has no mesh");
1332+
MT_CHECK(
1333+
activePolys.size() == character.mesh->polyFaceSizes.size(),
1334+
"Active polys size ({}) does not match polygon count ({})",
1335+
activePolys.size(),
1336+
character.mesh->polyFaceSizes.size());
1337+
1338+
// Convert polygon selection to vertex selection, then to face selection
1339+
const auto activeVertices = polysToVertices(*character.mesh, activePolys);
1340+
const auto activeFaces = verticesToFaces(*character.mesh, activeVertices);
1341+
1342+
return reduceMeshComponents(character, activeVertices, activeFaces);
1343+
}
1344+
11881345
// Explicit instantiations for commonly used types
11891346
template CharacterT<float> reduceMeshByVertices<float>(
11901347
const CharacterT<float>& character,
@@ -1234,4 +1391,36 @@ template std::vector<bool> facesToVertices<double>(
12341391
const MeshT<double>& mesh,
12351392
const std::vector<bool>& activeFaces);
12361393

1394+
template std::vector<bool> verticesToPolys<float>(
1395+
const MeshT<float>& mesh,
1396+
const std::vector<bool>& activeVertices);
1397+
1398+
template std::vector<bool> verticesToPolys<double>(
1399+
const MeshT<double>& mesh,
1400+
const std::vector<bool>& activeVertices);
1401+
1402+
template std::vector<bool> polysToVertices<float>(
1403+
const MeshT<float>& mesh,
1404+
const std::vector<bool>& activePolys);
1405+
1406+
template std::vector<bool> polysToVertices<double>(
1407+
const MeshT<double>& mesh,
1408+
const std::vector<bool>& activePolys);
1409+
1410+
template MeshT<float> reduceMeshByPolys<float>(
1411+
const MeshT<float>& mesh,
1412+
const std::vector<bool>& activePolys);
1413+
1414+
template MeshT<double> reduceMeshByPolys<double>(
1415+
const MeshT<double>& mesh,
1416+
const std::vector<bool>& activePolys);
1417+
1418+
template CharacterT<float> reduceMeshByPolys<float>(
1419+
const CharacterT<float>& character,
1420+
const std::vector<bool>& activePolys);
1421+
1422+
template CharacterT<double> reduceMeshByPolys<double>(
1423+
const CharacterT<double>& character,
1424+
const std::vector<bool>& activePolys);
1425+
12371426
} // namespace momentum

momentum/character/character_utility.h

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,12 +145,60 @@ template <typename T>
145145

146146
/// Converts face selection to vertex selection
147147
///
148-
/// @param[in] character Character containing the mesh
148+
/// @param[in] mesh The mesh containing the faces
149149
/// @param[in] activeFaces Boolean vector indicating which faces are active
150150
/// @return Boolean vector indicating which vertices are used by active faces
151151
template <typename T>
152152
[[nodiscard]] std::vector<bool> facesToVertices(
153153
const MeshT<T>& mesh,
154154
const std::vector<bool>& activeFaces);
155155

156+
/// Converts vertex selection to polygon selection
157+
///
158+
/// A polygon is active if all its vertices are active.
159+
///
160+
/// @param[in] mesh The mesh containing the polygon data
161+
/// @param[in] activeVertices Boolean vector indicating which vertices are active
162+
/// @return Boolean vector indicating which polygons only contain active vertices
163+
template <typename T>
164+
[[nodiscard]] std::vector<bool> verticesToPolys(
165+
const MeshT<T>& mesh,
166+
const std::vector<bool>& activeVertices);
167+
168+
/// Converts polygon selection to vertex selection
169+
///
170+
/// @param[in] mesh The mesh containing the polygon data
171+
/// @param[in] activePolys Boolean vector indicating which polygons are active
172+
/// @return Boolean vector indicating which vertices are used by active polygons
173+
template <typename T>
174+
[[nodiscard]] std::vector<bool> polysToVertices(
175+
const MeshT<T>& mesh,
176+
const std::vector<bool>& activePolys);
177+
178+
/// Reduces a standalone mesh to only include the specified polygons and associated vertices.
179+
///
180+
/// Converts polygon selection to vertex selection and face selection, then reduces the mesh.
181+
/// Both triangulated faces and polygon data are filtered and remapped.
182+
///
183+
/// @param[in] mesh The mesh to reduce
184+
/// @param[in] activePolys Boolean vector indicating which polygons to keep
185+
/// @return A new mesh containing only the specified polygons and their referenced vertices
186+
template <typename T>
187+
[[nodiscard]] MeshT<T> reduceMeshByPolys(
188+
const MeshT<T>& mesh,
189+
const std::vector<bool>& activePolys);
190+
191+
/// Reduces the mesh to only include the specified polygons and associated vertices
192+
///
193+
/// Converts polygon selection to vertex selection and face selection, then reduces the mesh.
194+
/// Both triangulated faces and polygon data are filtered and remapped.
195+
///
196+
/// @param[in] character Character to be reduced
197+
/// @param[in] activePolys Boolean vector indicating which polygons to keep
198+
/// @return A new character with mesh reduced to the specified polygons
199+
template <typename T>
200+
[[nodiscard]] CharacterT<T> reduceMeshByPolys(
201+
const CharacterT<T>& character,
202+
const std::vector<bool>& activePolys);
203+
156204
} // namespace momentum

momentum/test/character/character_test.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@
1010
#include "momentum/character/blend_shape.h"
1111
#include "momentum/character/blend_shape_skinning.h"
1212
#include "momentum/character/character_state.h"
13-
#include "momentum/character/character_utility.h"
1413
#include "momentum/character/collision_geometry.h"
15-
#include "momentum/character/linear_skinning.h"
1614
#include "momentum/character/locator.h"
1715
#include "momentum/character/parameter_transform.h"
1816
#include "momentum/character/skeleton.h"

0 commit comments

Comments
 (0)