Add isotropic remesh preprocess to cloth simulation
parent
579fa24e1c
commit
c4882dec1f
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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());
|
||||||
|
|
Loading…
Reference in New Issue