From c4882dec1f4a650cb5c2a3df5d739c0a13b278fd Mon Sep 17 00:00:00 2001 From: Jeremy Hu Date: Thu, 9 Jan 2020 08:37:14 +0930 Subject: [PATCH] Add isotropic remesh preprocess to cloth simulation --- dust3d.pro | 3 +++ src/isotropicremesh.cpp | 53 +++++++++++++++++++++++++++++++++++++++++ src/isotropicremesh.h | 13 ++++++++++ src/meshgenerator.cpp | 39 ++++++++++++++++++++++++++---- 4 files changed, 103 insertions(+), 5 deletions(-) create mode 100644 src/isotropicremesh.cpp create mode 100644 src/isotropicremesh.h diff --git a/dust3d.pro b/dust3d.pro index 5775e9ee..4d41320d 100644 --- a/dust3d.pro +++ b/dust3d.pro @@ -488,6 +488,9 @@ HEADERS += src/clothsimulator.h SOURCES += src/componentlayer.cpp HEADERS += src/componentlayer.h +SOURCES += src/isotropicremesh.cpp +HEADERS += src/isotropicremesh.h + SOURCES += src/main.cpp HEADERS += src/version.h diff --git a/src/isotropicremesh.cpp b/src/isotropicremesh.cpp new file mode 100644 index 00000000..28411d6b --- /dev/null +++ b/src/isotropicremesh.cpp @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include "booleanmesh.h" +#include "isotropicremesh.h" + +typedef boost::graph_traits::halfedge_descriptor halfedge_descriptor; +typedef boost::graph_traits::edge_descriptor edge_descriptor; +namespace PMP = CGAL::Polygon_mesh_processing; + +struct halfedge2edge +{ + halfedge2edge(const CgalMesh& m, std::vector& edges) + : m_mesh(m), m_edges(edges) + {} + void operator()(const halfedge_descriptor& h) const + { + m_edges.push_back(edge(h, m_mesh)); + } + const CgalMesh& m_mesh; + std::vector& m_edges; +}; + +void isotropicRemesh(const std::vector &inputVertices, + std::vector> &inputTriangles, + std::vector &outputVertices, + std::vector> &outputTriangles, + float targetEdgeLength, + unsigned int iterationNum) +{ + CgalMesh *mesh = buildCgalMesh(inputVertices, inputTriangles); + if (nullptr == mesh) + return; + + std::vector border; + PMP::border_halfedges(faces(*mesh), + *mesh, + boost::make_function_output_iterator(halfedge2edge(*mesh, border))); + PMP::split_long_edges(border, targetEdgeLength, *mesh); + + PMP::isotropic_remeshing(faces(*mesh), + targetEdgeLength, + *mesh, + PMP::parameters::number_of_iterations(iterationNum) + .protect_constraints(true)); + + outputVertices.clear(); + outputTriangles.clear(); + fetchFromCgalMesh(mesh, outputVertices, outputTriangles); + + delete mesh; +} diff --git a/src/isotropicremesh.h b/src/isotropicremesh.h new file mode 100644 index 00000000..eaea6e6c --- /dev/null +++ b/src/isotropicremesh.h @@ -0,0 +1,13 @@ +#ifndef DUST3D_ISOTROPICREMESH_H +#define DUST3D_ISOTROPICREMESH_H +#include +#include + +void isotropicRemesh(const std::vector &inputVertices, + std::vector> &inputTriangles, + std::vector &outputVertices, + std::vector> &outputTriangles, + float targetEdgeLength, + unsigned int iterationNum); + +#endif diff --git a/src/meshgenerator.cpp b/src/meshgenerator.cpp index c5a24741..fc32c8e9 100644 --- a/src/meshgenerator.cpp +++ b/src/meshgenerator.cpp @@ -19,6 +19,7 @@ #include "remesher.h" #include "polycount.h" #include "clothsimulator.h" +#include "isotropicremesh.h" MeshGenerator::MeshGenerator(Snapshot *snapshot) : m_snapshot(snapshot) @@ -1090,9 +1091,11 @@ MeshCombiner::Mesh *MeshGenerator::combineComponentMesh(const QString &component }); } delete mesh; - mesh = new MeshCombiner::Mesh(newVertices, newTriangles, componentId.isNull()); + bool disableSelfIntersectionTest = componentId.isNull() || + CombineMode::Uncombined == componentCombineMode(component); + mesh = new MeshCombiner::Mesh(newVertices, newTriangles, disableSelfIntersectionTest); if (nullptr != mesh) { - if (!componentId.isNull()) { + if (!disableSelfIntersectionTest) { if (mesh->isNull()) { delete mesh; mesh = nullptr; @@ -1584,15 +1587,30 @@ void MeshGenerator::collectClothComponent(const QString &componentIdString) const auto &component = findComponent(componentIdString); if (ComponentLayer::Cloth == componentLayer(component)) { const auto &componentCache = m_cacheContext->components[componentIdString]; - if (nullptr == componentCache.mesh || componentCache.mesh->isNull()) { + if (nullptr == componentCache.mesh) { return; } if (m_clothCollisionTriangles.empty()) return; std::vector uncombinedVertices; + std::vector> uncombinedOriginalFaces; std::vector> uncombinedFaces; - componentCache.mesh->fetch(uncombinedVertices, uncombinedFaces); + componentCache.mesh->fetch(uncombinedVertices, uncombinedOriginalFaces); + uncombinedFaces.reserve(uncombinedOriginalFaces.size()); + for (const auto &it: uncombinedOriginalFaces) { + if (4 == it.size()) { + uncombinedFaces.push_back(std::vector { + it[0], it[1], it[2] + }); + uncombinedFaces.push_back(std::vector { + it[2], it[3], it[0] + }); + } else if (3 == it.size()) { + uncombinedFaces.push_back(it); + } + } + isotropicRemesh(uncombinedVertices, uncombinedFaces, uncombinedVertices, uncombinedFaces, 0.02f, 3); std::map> positionMap; for (const auto &it: componentCache.outcomeNodeVertices) { @@ -1625,7 +1643,18 @@ void MeshGenerator::collectClothComponent(const QString &componentIdString) updateVertexIndices(uncombinedFaces); m_outcome->vertices.insert(m_outcome->vertices.end(), uncombinedVertices.begin(), uncombinedVertices.end()); - m_outcome->triangles.insert(m_outcome->triangles.end(), uncombinedFaces.begin(), uncombinedFaces.end()); + for (const auto &it: uncombinedFaces) { + if (4 == it.size()) { + m_outcome->triangles.push_back(std::vector { + it[0], it[1], it[2] + }); + m_outcome->triangles.push_back(std::vector { + it[2], it[3], it[0] + }); + } else if (3 == it.size()) { + m_outcome->triangles.push_back(it); + } + } m_outcome->triangleAndQuads.insert(m_outcome->triangleAndQuads.end(), uncombinedFaces.begin(), uncombinedFaces.end()); m_outcome->nodes.insert(m_outcome->nodes.end(), componentCache.outcomeNodes.begin(), componentCache.outcomeNodes.end());