Fallback to uncombined when component mesh is not combinable [skip ci]

master
huxingyi 2020-04-11 16:23:12 +09:30
parent a7730884b2
commit 082b5ea1f1
4 changed files with 90 additions and 45 deletions

View File

@ -23,10 +23,11 @@ MeshCombiner::Mesh::Mesh(const std::vector<QVector3D> &vertices, const std::vect
} else { } else {
if (CGAL::Polygon_mesh_processing::triangulate_faces(*cgalMesh)) { if (CGAL::Polygon_mesh_processing::triangulate_faces(*cgalMesh)) {
if (CGAL::Polygon_mesh_processing::does_self_intersect(*cgalMesh)) { if (CGAL::Polygon_mesh_processing::does_self_intersect(*cgalMesh)) {
m_isSelfIntersected = true;
qDebug() << "Mesh does_self_intersect"; qDebug() << "Mesh does_self_intersect";
delete cgalMesh; delete cgalMesh;
cgalMesh = nullptr; cgalMesh = nullptr;
} else {
m_isCombinable = true;
} }
} else { } else {
qDebug() << "Mesh triangulate failed"; qDebug() << "Mesh triangulate failed";
@ -43,7 +44,7 @@ MeshCombiner::Mesh::Mesh(const std::vector<QVector3D> &vertices, const std::vect
MeshCombiner::Mesh::Mesh(const Mesh &other) MeshCombiner::Mesh::Mesh(const Mesh &other)
{ {
if (other.m_privateData) { if (other.m_privateData) {
m_isSelfIntersected = other.m_isSelfIntersected; m_isCombinable = other.m_isCombinable;
m_privateData = new CgalMesh(*(CgalMesh *)other.m_privateData); m_privateData = new CgalMesh(*(CgalMesh *)other.m_privateData);
validate(); validate();
} }
@ -69,21 +70,16 @@ bool MeshCombiner::Mesh::isNull() const
return nullptr == m_privateData; return nullptr == m_privateData;
} }
bool MeshCombiner::Mesh::isSelfIntersected() const bool MeshCombiner::Mesh::isCombinable() const
{ {
return m_isSelfIntersected; return m_isCombinable;
}
void MeshCombiner::Mesh::markAsSelfIntersected()
{
m_isSelfIntersected = true;
} }
MeshCombiner::Mesh *MeshCombiner::combine(const Mesh &firstMesh, const Mesh &secondMesh, Method method, MeshCombiner::Mesh *MeshCombiner::combine(const Mesh &firstMesh, const Mesh &secondMesh, Method method,
std::vector<std::pair<Source, size_t>> *combinedVerticesComeFrom) std::vector<std::pair<Source, size_t>> *combinedVerticesComeFrom)
{ {
if (firstMesh.isNull() || firstMesh.isSelfIntersected() || if (firstMesh.isNull() || !firstMesh.isCombinable() ||
secondMesh.isNull() || secondMesh.isSelfIntersected()) secondMesh.isNull() || !secondMesh.isCombinable())
return nullptr; return nullptr;
CgalMesh *resultCgalMesh = nullptr; CgalMesh *resultCgalMesh = nullptr;
@ -157,9 +153,7 @@ MeshCombiner::Mesh *MeshCombiner::combine(const Mesh &firstMesh, const Mesh &sec
Mesh *mesh = new Mesh; Mesh *mesh = new Mesh;
mesh->m_privateData = resultCgalMesh; mesh->m_privateData = resultCgalMesh;
if (CGAL::Polygon_mesh_processing::does_self_intersect(*resultCgalMesh)) { mesh->m_isCombinable = true;
mesh->markAsSelfIntersected();
}
return mesh; return mesh;
} }
@ -172,5 +166,6 @@ void MeshCombiner::Mesh::validate()
if (isNullCgalMesh<CgalKernel>(exactMesh)) { if (isNullCgalMesh<CgalKernel>(exactMesh)) {
delete exactMesh; delete exactMesh;
m_privateData = nullptr; m_privateData = nullptr;
m_isCombinable = false;
} }
} }

View File

@ -28,14 +28,13 @@ public:
~Mesh(); ~Mesh();
void fetch(std::vector<QVector3D> &vertices, std::vector<std::vector<size_t>> &faces) const; void fetch(std::vector<QVector3D> &vertices, std::vector<std::vector<size_t>> &faces) const;
bool isNull() const; bool isNull() const;
bool isSelfIntersected() const; bool isCombinable() const;
void markAsSelfIntersected();
friend MeshCombiner; friend MeshCombiner;
private: private:
void *m_privateData = nullptr; void *m_privateData = nullptr;
bool m_isSelfIntersected = false; bool m_isCombinable = false;
void validate(); void validate();
}; };

View File

@ -1035,8 +1035,7 @@ MeshCombiner::Mesh *MeshGenerator::combineComponentMesh(const QString &component
componentCache.outcomeEdges.clear(); componentCache.outcomeEdges.clear();
componentCache.outcomeNodeVertices.clear(); componentCache.outcomeNodeVertices.clear();
componentCache.outcomePaintMaps.clear(); componentCache.outcomePaintMaps.clear();
delete componentCache.mesh; componentCache.releaseMeshes();
componentCache.mesh = nullptr;
QString linkDataType = valueOfKeyInMapOrEmpty(*component, "linkDataType"); QString linkDataType = valueOfKeyInMapOrEmpty(*component, "linkDataType");
if ("partId" == linkDataType) { if ("partId" == linkDataType) {
@ -1084,10 +1083,10 @@ MeshCombiner::Mesh *MeshGenerator::combineComponentMesh(const QString &component
} }
auto combineMode = componentCombineMode(child); auto combineMode = componentCombineMode(child);
if (lastCombineMode != combineMode || lastCombineMode == CombineMode::Inversion) { if (lastCombineMode != combineMode || lastCombineMode == CombineMode::Inversion) {
qDebug() << "New group[" << currentGroupIndex << "] for combine mode[" << CombineModeToString(combineMode) << "]";
combineGroups.push_back({combineMode, {}}); combineGroups.push_back({combineMode, {}});
++currentGroupIndex; ++currentGroupIndex;
lastCombineMode = combineMode; lastCombineMode = combineMode;
qDebug() << "New group[" << currentGroupIndex << "] for combine mode[" << CombineModeToString(combineMode) << "]";
} }
if (-1 == currentGroupIndex) { if (-1 == currentGroupIndex) {
qDebug() << "Should not happen: -1 == currentGroupIndex"; qDebug() << "Should not happen: -1 == currentGroupIndex";
@ -1214,9 +1213,19 @@ MeshCombiner::Mesh *MeshGenerator::combineComponentMesh(const QString &component
}); });
} }
delete mesh; delete mesh;
mesh = nullptr;
bool disableSelfIntersectionTest = componentId.isNull() || bool disableSelfIntersectionTest = componentId.isNull() ||
CombineMode::Uncombined == componentCombineMode(component); CombineMode::Uncombined == componentCombineMode(component);
if (!disableSelfIntersectionTest) {
if (isManifold(newTriangles)) {
mesh = new MeshCombiner::Mesh(newVertices, newTriangles, disableSelfIntersectionTest); mesh = new MeshCombiner::Mesh(newVertices, newTriangles, disableSelfIntersectionTest);
} else {
disableSelfIntersectionTest = true;
mesh = new MeshCombiner::Mesh(newVertices, newTriangles, disableSelfIntersectionTest);
}
} else {
mesh = new MeshCombiner::Mesh(newVertices, newTriangles, disableSelfIntersectionTest);
}
if (nullptr != mesh) { if (nullptr != mesh) {
if (!disableSelfIntersectionTest) { if (!disableSelfIntersectionTest) {
if (mesh->isNull()) { if (mesh->isNull()) {
@ -1244,12 +1253,14 @@ MeshCombiner::Mesh *MeshGenerator::combineMultipleMeshes(const std::vector<std::
MeshCombiner::Mesh *subMesh = std::get<0>(it); MeshCombiner::Mesh *subMesh = std::get<0>(it);
const QString &subMeshIdString = std::get<2>(it); const QString &subMeshIdString = std::get<2>(it);
//qDebug() << "Combine mode:" << CombineModeToString(childCombineMode); //qDebug() << "Combine mode:" << CombineModeToString(childCombineMode);
if (nullptr == subMesh) { if (nullptr == subMesh || subMesh->isNull()) {
delete subMesh;
qDebug() << "Child mesh is null"; qDebug() << "Child mesh is null";
continue; continue;
} }
if (subMesh->isNull()) { if (!subMesh->isCombinable()) {
qDebug() << "Child mesh is uncombinable"; qDebug() << "Child mesh is uncombinable";
// TODO: Collect vertices
delete subMesh; delete subMesh;
continue; continue;
} }
@ -1331,6 +1342,11 @@ MeshCombiner::Mesh *MeshGenerator::combineComponentChildGroupMesh(const std::vec
continue; continue;
} }
if (!subMesh->isCombinable()) {
componentCache.incombinableMeshes.push_back(subMesh);
continue;
}
multipleMeshes.push_back(std::make_tuple(subMesh, childCombineMode, childIdString)); multipleMeshes.push_back(std::make_tuple(subMesh, childCombineMode, childIdString));
} }
return combineMultipleMeshes(multipleMeshes); return combineMultipleMeshes(multipleMeshes);
@ -1359,7 +1375,7 @@ MeshCombiner::Mesh *MeshGenerator::combineTwoMeshes(const MeshCombiner::Mesh &fi
if (recombiner.recombine()) { if (recombiner.recombine()) {
if (isManifold(recombiner.regeneratedFaces())) { if (isManifold(recombiner.regeneratedFaces())) {
MeshCombiner::Mesh *reMesh = new MeshCombiner::Mesh(recombiner.regeneratedVertices(), recombiner.regeneratedFaces(), false); MeshCombiner::Mesh *reMesh = new MeshCombiner::Mesh(recombiner.regeneratedVertices(), recombiner.regeneratedFaces(), false);
if (!reMesh->isNull() && !reMesh->isSelfIntersected()) { if (!reMesh->isNull() && reMesh->isCombinable()) {
delete newMesh; delete newMesh;
newMesh = reMesh; newMesh = reMesh;
} else { } else {
@ -1537,6 +1553,7 @@ void MeshGenerator::generate()
// Recursively check uncombined components // Recursively check uncombined components
collectUncombinedComponent(QUuid().toString()); collectUncombinedComponent(QUuid().toString());
collectIncombinableComponentMeshes(QUuid().toString());
// Fetch nodes as body nodes before cloth nodes collecting // Fetch nodes as body nodes before cloth nodes collecting
std::set<std::pair<QUuid, QUuid>> bodyNodeMap; std::set<std::pair<QUuid, QUuid>> bodyNodeMap;
@ -1691,26 +1708,29 @@ void MeshGenerator::remesh(const std::vector<OutcomeNode> &inputNodes,
} }
} }
void MeshGenerator::collectUncombinedComponent(const QString &componentIdString) void MeshGenerator::collectIncombinableComponentMeshes(const QString &componentIdString)
{ {
const auto &component = findComponent(componentIdString);
if (CombineMode::Uncombined == componentCombineMode(component)) {
if (ComponentLayer::Body != componentLayer(component))
return;
const auto &componentCache = m_cacheContext->components[componentIdString]; const auto &componentCache = m_cacheContext->components[componentIdString];
if (nullptr == componentCache.mesh || componentCache.mesh->isNull()) { for (const auto &mesh: componentCache.incombinableMeshes)
qDebug() << "Uncombined mesh is null"; collectIncombinableMesh(mesh, componentCache);
return; const auto &component = findComponent(componentIdString);
for (const auto &childIdString: valueOfKeyInMapOrEmpty(*component, "children").split(",")) {
if (childIdString.isEmpty())
continue;
collectIncombinableComponentMeshes(childIdString);
}
} }
m_outcome->nodes.insert(m_outcome->nodes.end(), componentCache.outcomeNodes.begin(), componentCache.outcomeNodes.end()); void MeshGenerator::collectIncombinableMesh(const MeshCombiner::Mesh *mesh, const GeneratedComponent &componentCache)
m_outcome->edges.insert(m_outcome->edges.end(), componentCache.outcomeEdges.begin(), componentCache.outcomeEdges.end()); {
m_outcome->nodeVertices.insert(m_outcome->nodeVertices.end(), componentCache.outcomeNodeVertices.begin(), componentCache.outcomeNodeVertices.end()); if (nullptr == mesh)
m_outcome->paintMaps.insert(m_outcome->paintMaps.end(), componentCache.outcomePaintMaps.begin(), componentCache.outcomePaintMaps.end()); return;
m_isSuccessful = false;
std::vector<QVector3D> uncombinedVertices; std::vector<QVector3D> uncombinedVertices;
std::vector<std::vector<size_t>> uncombinedFaces; std::vector<std::vector<size_t>> uncombinedFaces;
componentCache.mesh->fetch(uncombinedVertices, uncombinedFaces); mesh->fetch(uncombinedVertices, uncombinedFaces);
std::vector<std::vector<size_t>> uncombinedTriangleAndQuads; std::vector<std::vector<size_t>> uncombinedTriangleAndQuads;
recoverQuads(uncombinedVertices, uncombinedFaces, componentCache.sharedQuadEdges, uncombinedTriangleAndQuads); recoverQuads(uncombinedVertices, uncombinedFaces, componentCache.sharedQuadEdges, uncombinedTriangleAndQuads);
@ -1728,6 +1748,26 @@ void MeshGenerator::collectUncombinedComponent(const QString &componentIdString)
m_outcome->vertices.insert(m_outcome->vertices.end(), uncombinedVertices.begin(), uncombinedVertices.end()); m_outcome->vertices.insert(m_outcome->vertices.end(), uncombinedVertices.begin(), uncombinedVertices.end());
m_outcome->triangles.insert(m_outcome->triangles.end(), uncombinedFaces.begin(), uncombinedFaces.end()); m_outcome->triangles.insert(m_outcome->triangles.end(), uncombinedFaces.begin(), uncombinedFaces.end());
m_outcome->triangleAndQuads.insert(m_outcome->triangleAndQuads.end(), uncombinedTriangleAndQuads.begin(), uncombinedTriangleAndQuads.end()); m_outcome->triangleAndQuads.insert(m_outcome->triangleAndQuads.end(), uncombinedTriangleAndQuads.begin(), uncombinedTriangleAndQuads.end());
}
void MeshGenerator::collectUncombinedComponent(const QString &componentIdString)
{
const auto &component = findComponent(componentIdString);
if (CombineMode::Uncombined == componentCombineMode(component)) {
if (ComponentLayer::Body != componentLayer(component))
return;
const auto &componentCache = m_cacheContext->components[componentIdString];
if (nullptr == componentCache.mesh || componentCache.mesh->isNull()) {
qDebug() << "Uncombined mesh is null";
return;
}
m_outcome->nodes.insert(m_outcome->nodes.end(), componentCache.outcomeNodes.begin(), componentCache.outcomeNodes.end());
m_outcome->edges.insert(m_outcome->edges.end(), componentCache.outcomeEdges.begin(), componentCache.outcomeEdges.end());
m_outcome->nodeVertices.insert(m_outcome->nodeVertices.end(), componentCache.outcomeNodeVertices.begin(), componentCache.outcomeNodeVertices.end());
m_outcome->paintMaps.insert(m_outcome->paintMaps.end(), componentCache.outcomePaintMaps.begin(), componentCache.outcomePaintMaps.end());
collectIncombinableMesh(componentCache.mesh, componentCache);
return; return;
} }
for (const auto &childIdString: valueOfKeyInMapOrEmpty(*component, "children").split(",")) { for (const auto &childIdString: valueOfKeyInMapOrEmpty(*component, "children").split(",")) {

View File

@ -40,9 +40,18 @@ class GeneratedComponent
public: public:
~GeneratedComponent() ~GeneratedComponent()
{ {
delete mesh; releaseMeshes();
}; };
void releaseMeshes()
{
delete mesh;
mesh = nullptr;
for (auto &it: incombinableMeshes)
delete it;
incombinableMeshes.clear();
}
MeshCombiner::Mesh *mesh = nullptr; MeshCombiner::Mesh *mesh = nullptr;
std::vector<MeshCombiner::Mesh *> incombinableMeshes;
std::set<std::pair<PositionKey, PositionKey>> sharedQuadEdges; std::set<std::pair<PositionKey, PositionKey>> sharedQuadEdges;
std::set<PositionKey> noneSeamVertices; std::set<PositionKey> noneSeamVertices;
std::vector<OutcomeNode> outcomeNodes; std::vector<OutcomeNode> outcomeNodes;
@ -111,6 +120,8 @@ private:
bool m_weldEnabled = true; bool m_weldEnabled = true;
void collectParts(); void collectParts();
void collectIncombinableComponentMeshes(const QString &componentIdString);
void collectIncombinableMesh(const MeshCombiner::Mesh *mesh, const GeneratedComponent &componentCache);
bool checkIsComponentDirty(const QString &componentIdString); bool checkIsComponentDirty(const QString &componentIdString);
bool checkIsPartDirty(const QString &partIdString); bool checkIsPartDirty(const QString &partIdString);
bool checkIsPartDependencyDirty(const QString &partIdString); bool checkIsPartDependencyDirty(const QString &partIdString);