Add isotropic remesh preprocess to cloth simulation

master
Jeremy Hu 2020-01-09 08:37:14 +09:30
parent 579fa24e1c
commit c4882dec1f
4 changed files with 103 additions and 5 deletions

View File

@ -488,6 +488,9 @@ HEADERS += src/clothsimulator.h
SOURCES += src/componentlayer.cpp SOURCES += src/componentlayer.cpp
HEADERS += src/componentlayer.h HEADERS += src/componentlayer.h
SOURCES += src/isotropicremesh.cpp
HEADERS += src/isotropicremesh.h
SOURCES += src/main.cpp SOURCES += src/main.cpp
HEADERS += src/version.h HEADERS += src/version.h

53
src/isotropicremesh.cpp Normal file
View File

@ -0,0 +1,53 @@
#include <CGAL/boost/graph/graph_traits_Surface_mesh.h>
#include <CGAL/Polygon_mesh_processing/remesh.h>
#include <CGAL/Polygon_mesh_processing/border.h>
#include <boost/function_output_iterator.hpp>
#include "booleanmesh.h"
#include "isotropicremesh.h"
typedef boost::graph_traits<CgalMesh>::halfedge_descriptor halfedge_descriptor;
typedef boost::graph_traits<CgalMesh>::edge_descriptor edge_descriptor;
namespace PMP = CGAL::Polygon_mesh_processing;
struct halfedge2edge
{
halfedge2edge(const CgalMesh& m, std::vector<edge_descriptor>& 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<edge_descriptor>& m_edges;
};
void isotropicRemesh(const std::vector<QVector3D> &inputVertices,
std::vector<std::vector<size_t>> &inputTriangles,
std::vector<QVector3D> &outputVertices,
std::vector<std::vector<size_t>> &outputTriangles,
float targetEdgeLength,
unsigned int iterationNum)
{
CgalMesh *mesh = buildCgalMesh<CgalKernel>(inputVertices, inputTriangles);
if (nullptr == mesh)
return;
std::vector<edge_descriptor> 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<CgalKernel>(mesh, outputVertices, outputTriangles);
delete mesh;
}

13
src/isotropicremesh.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef DUST3D_ISOTROPICREMESH_H
#define DUST3D_ISOTROPICREMESH_H
#include <QVector3D>
#include <vector>
void isotropicRemesh(const std::vector<QVector3D> &inputVertices,
std::vector<std::vector<size_t>> &inputTriangles,
std::vector<QVector3D> &outputVertices,
std::vector<std::vector<size_t>> &outputTriangles,
float targetEdgeLength,
unsigned int iterationNum);
#endif

View File

@ -19,6 +19,7 @@
#include "remesher.h" #include "remesher.h"
#include "polycount.h" #include "polycount.h"
#include "clothsimulator.h" #include "clothsimulator.h"
#include "isotropicremesh.h"
MeshGenerator::MeshGenerator(Snapshot *snapshot) : MeshGenerator::MeshGenerator(Snapshot *snapshot) :
m_snapshot(snapshot) m_snapshot(snapshot)
@ -1090,9 +1091,11 @@ MeshCombiner::Mesh *MeshGenerator::combineComponentMesh(const QString &component
}); });
} }
delete mesh; 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 (nullptr != mesh) {
if (!componentId.isNull()) { if (!disableSelfIntersectionTest) {
if (mesh->isNull()) { if (mesh->isNull()) {
delete mesh; delete mesh;
mesh = nullptr; mesh = nullptr;
@ -1584,15 +1587,30 @@ void MeshGenerator::collectClothComponent(const QString &componentIdString)
const auto &component = findComponent(componentIdString); const auto &component = findComponent(componentIdString);
if (ComponentLayer::Cloth == componentLayer(component)) { if (ComponentLayer::Cloth == componentLayer(component)) {
const auto &componentCache = m_cacheContext->components[componentIdString]; const auto &componentCache = m_cacheContext->components[componentIdString];
if (nullptr == componentCache.mesh || componentCache.mesh->isNull()) { if (nullptr == componentCache.mesh) {
return; return;
} }
if (m_clothCollisionTriangles.empty()) if (m_clothCollisionTriangles.empty())
return; return;
std::vector<QVector3D> uncombinedVertices; std::vector<QVector3D> uncombinedVertices;
std::vector<std::vector<size_t>> uncombinedOriginalFaces;
std::vector<std::vector<size_t>> uncombinedFaces; std::vector<std::vector<size_t>> 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<size_t> {
it[0], it[1], it[2]
});
uncombinedFaces.push_back(std::vector<size_t> {
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<PositionKey, std::pair<QUuid, QUuid>> positionMap; std::map<PositionKey, std::pair<QUuid, QUuid>> positionMap;
for (const auto &it: componentCache.outcomeNodeVertices) { for (const auto &it: componentCache.outcomeNodeVertices) {
@ -1625,7 +1643,18 @@ void MeshGenerator::collectClothComponent(const QString &componentIdString)
updateVertexIndices(uncombinedFaces); updateVertexIndices(uncombinedFaces);
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()); for (const auto &it: uncombinedFaces) {
if (4 == it.size()) {
m_outcome->triangles.push_back(std::vector<size_t> {
it[0], it[1], it[2]
});
m_outcome->triangles.push_back(std::vector<size_t> {
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->triangleAndQuads.insert(m_outcome->triangleAndQuads.end(), uncombinedFaces.begin(), uncombinedFaces.end());
m_outcome->nodes.insert(m_outcome->nodes.end(), componentCache.outcomeNodes.begin(), componentCache.outcomeNodes.end()); m_outcome->nodes.insert(m_outcome->nodes.end(), componentCache.outcomeNodes.begin(), componentCache.outcomeNodes.end());