added clean option in isotropic remeshing and updated the remeshing example

This commit is contained in:
T.Alderighi 2020-01-17 13:56:13 +01:00
parent 87f8ba9b33
commit cfe695ece3
2 changed files with 167 additions and 55 deletions

View File

@ -41,57 +41,79 @@ class MyEdge;
class MyFace;
class MyVertex;
struct MyUsedTypes : public UsedTypes< Use<MyVertex> ::AsVertexType,
Use<MyEdge> ::AsEdgeType,
Use<MyFace> ::AsFaceType>{};
Use<MyEdge> ::AsEdgeType,
Use<MyFace> ::AsFaceType>{};
class MyVertex : public Vertex<MyUsedTypes, vertex::Coord3f, vertex::Normal3f, vertex::VFAdj, vertex::Qualityf, vertex::BitFlags >{};
class MyVertex : public Vertex<MyUsedTypes, vertex::Coord3f, vertex::Normal3f, vertex::VFAdj, vertex::Qualityf, vertex::BitFlags, vertex::Mark>{};
class MyFace : public Face< MyUsedTypes, face::Mark, face::VertexRef, face::VFAdj, face::FFAdj, face::Normal3f, face::BitFlags > {};
class MyEdge : public Edge<MyUsedTypes>{};
class MyMesh : public tri::TriMesh< vector<MyVertex>, vector<MyFace> , vector<MyEdge> > {};
int main( int argc, char **argv )
{
MyMesh original,toremesh;
if(argc<2)
{
printf("Usage: trimesh_remesh <filename> [targetLen [iterNum] ]");
exit(0);
}
MyMesh original,toremesh;
if(argc<2)
{
printf("Usage: trimesh_remesh <filename> [[targetLen (bbox perc)] [iterNum] [creaseAngle] [maxSurfDist (bbox perc)]]");
exit(0);
}
if(tri::io::Importer<MyMesh>::Open(original,argv[1])!=0)
{
printf("Error reading file %s\n",argv[1]);
exit(0);
}
float targetLenPerc=.2f;
int iterNum=20;
if(argc>=3) targetLenPerc = atof(argv[2]);
if(argc>=4) iterNum = atoi(argv[3]);
// Mesh cleaning
tri::Clean<MyMesh>::RemoveDuplicateVertex(original);
tri::Clean<MyMesh>::RemoveUnreferencedVertex(original);
Allocator<MyMesh>::CompactEveryVector(original);
tri::UpdateNormal<MyMesh>::PerVertexNormalizedPerFaceNormalized(original);
tri::UpdateBounding<MyMesh>::Box(original);
vcg::tri::Append<MyMesh,MyMesh>::MeshCopy(toremesh,original);
tri::UpdateNormal<MyMesh>::PerVertexNormalizedPerFaceNormalized(toremesh);
tri::UpdateBounding<MyMesh>::Box(toremesh);
tri::UpdateTopology<MyMesh>::FaceFace(toremesh);
tri::MeshAssert<MyMesh>::FFTwoManifoldEdge(toremesh);
float lengthThr = targetLenPerc*(original.bbox.Diag()/100.f);
printf("Length Thr: %8.3f ~ %4.2f %% on %5.3f\n",lengthThr,targetLenPerc,original.bbox.Diag());
IsotropicRemeshing<MyMesh>::Params params;
params.SetTargetLen(lengthThr);
params.SetFeatureAngleDeg(10);
params.iter=iterNum;
printf(" Input mesh %8i v %8i f\n",toremesh.VN(),toremesh.FN());
IsotropicRemeshing<MyMesh>::Do(toremesh, original, params);
vcg::tri::io::ExporterPLY<MyMesh>::Save(toremesh, "remesh.ply");
printf("Output mesh %8i v %8i f\n",toremesh.VN(),toremesh.FN());
return 0;
if(tri::io::Importer<MyMesh>::Open(original,argv[1])!=0)
{
printf("Error reading file %s\n",argv[1]);
exit(0);
}
float targetLenPerc=.2f;
int iterNum=20;
float creaseAngle = 30.f;
float maxSurfDistPerc = 0.001f;
if(argc>=3) targetLenPerc = atof(argv[2]);
if(argc>=4) iterNum = atoi(argv[3]);
if(argc>=5) creaseAngle = atof(argv[4]);
if(argc>=6) maxSurfDistPerc = atof(argv[5]);
// Mesh cleaning
tri::Clean<MyMesh>::RemoveUnreferencedVertex(original);
Allocator<MyMesh>::CompactEveryVector(original);
tri::UpdateNormal<MyMesh>::PerVertexNormalizedPerFaceNormalized(original);
tri::UpdateBounding<MyMesh>::Box(original);
vcg::tri::Append<MyMesh,MyMesh>::MeshCopy(toremesh,original);
tri::UpdateNormal<MyMesh>::PerVertexNormalizedPerFaceNormalized(toremesh);
tri::UpdateBounding<MyMesh>::Box(toremesh);
tri::UpdateTopology<MyMesh>::FaceFace(toremesh);
float lengthThr = targetLenPerc*(original.bbox.Diag()/100.f);
float maxSurfDist = maxSurfDistPerc*(original.bbox.Diag()/100.f);
printf("Length Thr: %8.3f ~ %4.2f %% on %5.3f\n",lengthThr,targetLenPerc,original.bbox.Diag());
IsotropicRemeshing<MyMesh>::Params params;
params.SetTargetLen(lengthThr);
params.SetFeatureAngleDeg(creaseAngle);
params.iter=iterNum;
if (maxSurfDistPerc != 0)
{
params.surfDistCheck = true;
params.maxSurfDist = maxSurfDist;
}
else
{
params.surfDistCheck = false;
}
params.cleanFlag = true;
params.userSelectedCreases = false;
printf(" Input mesh %8i v %8i f\n",toremesh.VN(),toremesh.FN());
IsotropicRemeshing<MyMesh>::Do(toremesh, original, params);
vcg::tri::io::ExporterPLY<MyMesh>::Save(toremesh, "remesh.ply");
printf("Output mesh %8i v %8i f\n",toremesh.VN(),toremesh.FN());
return 0;
}

View File

@ -23,15 +23,16 @@
#ifndef _VCG_ISOTROPICREMESHING_H
#define _VCG_ISOTROPICREMESHING_H
#include<vcg/complex/algorithms/update/quality.h>
#include<vcg/complex/algorithms/update/curvature.h>
#include<vcg/complex/algorithms/update/normal.h>
#include<vcg/complex/algorithms/refine.h>
#include<vcg/complex/algorithms/stat.h>
#include<vcg/complex/algorithms/smooth.h>
#include<vcg/complex/algorithms/local_optimization/tri_edge_collapse.h>
#include<vcg/space/index/spatial_hashing.h>
#include <vcg/complex/algorithms/update/quality.h>
#include <vcg/complex/algorithms/update/curvature.h>
#include <vcg/complex/algorithms/update/normal.h>
#include <vcg/complex/algorithms/refine.h>
#include <vcg/complex/algorithms/stat.h>
#include <vcg/complex/algorithms/smooth.h>
#include <vcg/complex/algorithms/local_optimization/tri_edge_collapse.h>
#include <vcg/space/index/spatial_hashing.h>
#include <vcg/complex/append.h>
#include <vcg/complex/allocate.h>
#include <wrap/io_trimesh/export.h>
namespace vcg {
@ -42,6 +43,7 @@ class IsotropicRemeshing
public:
typedef TRI_MESH_TYPE MeshType;
typedef typename MeshType::FaceType FaceType;
typedef typename MeshType::FacePointer FacePointer;
typedef typename FaceType::VertexType VertexType;
typedef typename FaceType::VertexPointer VertexPointer;
typedef typename VertexType::ScalarType ScalarType;
@ -85,6 +87,7 @@ public:
bool smoothFlag=true;
bool projectFlag=true;
bool selectedOnly = false;
bool cleanFlag = true;
bool userSelectedCreases = false;
bool surfDistCheck = true;
@ -111,6 +114,7 @@ public:
} Params;
private:
static void debug_crease (MeshType & toRemesh, std::string prepend, int i)
{
ForEachVertex(toRemesh, [] (VertexType & v) {
@ -136,6 +140,88 @@ public:
vcg::tri::io::Exporter<MeshType>::Save(toRemesh, prepend.c_str(), vcg::tri::io::Mask::IOM_ALL);
}
static void removeColinearFaces(MeshType & m, Params & params)
{
vcg::tri::UpdateTopology<MeshType>::FaceFace(m);
int count = 0;
// MeshType projectMesh;
// vcg::tri::Append<MeshType, MeshType>::MeshCopy(projectMesh, m);
// vcg::tri::UpdateBounding<MeshType>::Box(projectMesh);
// vcg::tri::UpdateNormal<MeshType>::PerVertexNormalizedPerFace(projectMesh);
// StaticGrid grid;
// grid.Set(projectMesh.face.begin(), projectMesh.face.end());
do
{
vcg::tri::UpdateTopology<MeshType>::FaceFace(m);
vcg::tri::UnMarkAll(m);
count = 0;
for (size_t i = 0; i < size_t(m.FN()); ++i)
{
FaceType & f = m.face[i];
ScalarType quality = vcg::QualityRadii(f.cP(0), f.cP(1), f.cP(2));
if (quality <= 0.00000001)
{
//find longest edge
double edges[3];
edges[0] = vcg::Distance(f.cP(0), f.cP(1));
edges[1] = vcg::Distance(f.cP(1), f.cP(2));
edges[2] = vcg::Distance(f.cP(2), f.cP(0));
int longestIdx = std::find(edges, edges+3, std::max(std::max(edges[0], edges[1]), edges[2])) - (edges);
if (vcg::tri::IsMarked(m, f.V2(longestIdx)))
continue;
auto f1 = f.cFFp(longestIdx);
vcg::tri::Mark(m,f.V2(longestIdx));
if (!vcg::face::IsBorder(f, longestIdx) && vcg::face::IsManifold(f, longestIdx) && vcg::face::checkFlipEdgeNotManifold<FaceType>(f, longestIdx)) {
// Check if EdgeFlipping improves quality
FacePointer g = f.FFp(longestIdx); int k = f.FFi(longestIdx);
vcg::Triangle3<ScalarType> t1(f.P(longestIdx), f.P1(longestIdx), f.P2(longestIdx)), t2(g->P(k), g->P1(k), g->P2(k)),
t3(f.P(longestIdx), g->P2(k), f.P2(longestIdx)), t4(g->P(k), f.P2(longestIdx), g->P2(k));
if ( std::min( QualityFace(t1), QualityFace(t2) ) <= std::min( QualityFace(t3), QualityFace(t4) ))
{
ScalarType dist;
CoordType closest;
auto fp0 = vcg::tri::GetClosestFaceBase(*params.mProject, params.grid, vcg::Barycenter(t3), 0.000001, dist, closest);
if (fp0 == NULL)
continue;
auto fp1 = vcg::tri::GetClosestFaceBase(*params.mProject, params.grid, vcg::Barycenter(t4), 0.000001, dist, closest);
if (fp1 == NULL)
continue;
vcg::face::FlipEdgeNotManifold<FaceType>(f, longestIdx);
++count;
}
}
}
}
} while (count);
}
static void cleanMesh(MeshType & m, Params & params)
{
vcg::tri::Clean<MeshType>::RemoveDuplicateFace(m);
vcg::tri::Clean<MeshType>::RemoveUnreferencedVertex(m);
vcg::tri::Allocator<MeshType>::CompactEveryVector(m);
vcg::tri::UpdateTopology<MeshType>::FaceFace(m);
removeColinearFaces(m, params);
vcg::tri::UpdateTopology<MeshType>::FaceFace(m);
}
public:
static void Do(MeshType &toRemesh, Params & params, vcg::CallBackPos * cb=0)
{
MeshType toProjectCopy;
@ -151,6 +237,7 @@ public:
assert(&toRemesh != &toProject);
params.stat.Reset();
tri::UpdateBounding<MeshType>::Box(toRemesh);
{
@ -161,6 +248,9 @@ public:
params.grid.Set(toProject.face.begin(), toProject.face.end());
}
if (params.cleanFlag)
cleanMesh(toRemesh, params);
tri::UpdateTopology<MeshType>::FaceFace(toRemesh);
tri::UpdateFlags<MeshType>::VertexBorderFromFaceAdj(toRemesh);
tri::UpdateTopology<MeshType>::VertexFace(toRemesh);
@ -173,7 +263,6 @@ public:
for(int i=0; i < params.iter; ++i)
{
// params.stat.Reset();
if(cb) cb(100*i/params.iter, "Remeshing");
if(params.splitFlag)
@ -1023,6 +1112,7 @@ private:
{
bp = VertexPair(pi.VFlip(), pi.V());
Collapser::Do(m, bp, mp, true);
++params.stat.collapseNum;
++count;
break;
}