37
46
#include <vcg/complex/trimesh/update/normal.h>
38
47
#include <vcg/complex/trimesh/point_sampling.h>
39
48
#include <vcg/space/triangle3.h>
49
#include <vcg/complex/trimesh/allocate.h>
42
52
using namespace std;
43
53
using namespace vcg;
48
BaseSampler(CMeshO* _m){m=_m;};
51
/*void AddVert(const CMeshO::VertexType &p)
53
tri::Allocator<CMeshO>::AddVertices(*m,1);
54
m->vert.back().ImportLocal(p);
57
void AddFace(const CMeshO::FaceType &f, CMeshO::CoordType p)
59
tri::Allocator<CMeshO>::AddVertices(*m,1);
60
m->vert.back().P() = f.P(0)*p[0] + f.P(1)*p[1] +f.P(2)*p[2];
61
m->vert.back().N() = f.V(0)->N()*p[0] + f.V(1)->N()*p[1] +f.V(2)->N()*p[2];
64
/*void AddTextureSample(const CMeshO::FaceType &f, const CMeshO::CoordType &p, const Point2i &tp)
66
tri::Allocator<CMeshO>::AddVertices(*m,1);
68
if(uvSpaceFlag) m->vert.back().P() = Point3f(float(tp[0]),float(tp[1]),0);
69
else m->vert.back().P() = f.P(0)*p[0] + f.P(1)*p[1] +f.P(2)*p[2];
70
m->vert.back().N() = f.V(0)->N()*p[0] + f.V(1)->N()*p[1] +f.V(2)->N()*p[2];
72
}; // end class BaseSampler
74
FilterDirt::FilterDirt(): defaultGammaTon(500)
56
FilterDirt::FilterDirt()
82
64
actionList << new QAction(filterName(tt), this);
85
const QString FilterDirt::filterName(FilterIDType filterId)
87
if(filterId!= FP_DIRT)
89
return QString("error!");
91
return QString("Dirt Maker");
93
const QString FilterDirt::filterInfo(FilterIDType filterId)
96
if(filterId!= FP_DIRT)
98
return QString("error!");
100
return QString("Simulate dirt accumolation over the mesh");
103
const int FilterDirt::getRequirements(QAction */*action*/)
106
return MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACECOLOR | MeshModel::MM_FACEMARK;
109
bool FilterDirt::applyFilter(QAction * /*filter*/, MeshDocument &md, FilterParameterSet & /*par*/, vcg::CallBackPos */*cb*/)
111
//NOTE: i know this method require a code refactoring. Appling this filter in meshlab you can see 50 gamma-tons start from a position
112
//(green face) moving down (red face). In meshlab you can see vertex position using show vertex label.
114
typedef GridStaticPtr<CMeshO::FaceType, CMeshO::ScalarType > MetroMeshGrid;
115
typedef trimesh::FaceTmark<CMeshO> MarkerFace;
117
MarkerFace markerFunctor;
119
vcg::tri::UpdateColor<CMeshO>::FaceConstant(md.mm()->cm,vcg::Color4b::White); //!DEBUG! painting white for debug
121
MeshModel *curMM= md.mm();
122
MeshModel *mm= md.addNewMesh("Dust gamma-ton"); // After Adding a mesh to a MeshDocument the new mesh is the current one
124
BaseSampler mps(&(mm->cm));
125
vcg::tri::SurfaceSampling<CMeshO,BaseSampler>::Montecarlo(curMM->cm, mps, defaultGammaTon);
126
vcg::tri::UpdateBounding<CMeshO>::Box(mm->cm);
128
//calculate mean of face's edge segment perimeter
129
CMeshO::FaceIterator fi;
130
double perimeterSum=0;
131
for(fi=curMM->cm.face.begin();fi!=curMM->cm.face.end();++fi)
134
perimeterSum += vcg::Perimeter((*fi));
137
//calculate single gamma-ton step size (i want stepSize equal to 1/4 mean edges segment size)
138
float stepSize = (perimeterSum/12)/curMM->cm.fn;
140
CMeshO::VertexIterator vi;
141
CMeshO::FaceType *nearestF=NULL;
142
CMeshO::FaceType *precedentF=NULL;
143
float maxDist=(*curMM).cm.bbox.Diag()/3, minDist;
144
MetroMeshGrid unifGrid;
145
vcg::Point3f closestPt;
147
//setting up grid for space indexing
148
unifGrid.Set((*curMM).cm.face.begin(),(*curMM).cm.face.end());
149
markerFunctor.SetMesh(&curMM->cm);
151
//Require by PointDistance Functor
152
vcg::tri::UpdateNormals<CMeshO>::PerFaceNormalized(curMM->cm);
153
vcg::tri::UpdateFlags<CMeshO>::FaceProjection(curMM->cm);
155
int iterationNum = (int) curMM->cm.fn/300;
157
for (vi=mm->cm.vert.begin();vi!=mm->cm.vert.end();++vi)
159
precedentF=NULL; //Visual Debug Stuff
160
for (int i=0; i<iterationNum; ++i)
162
//get nearest face for every gamma-ton
163
vcg::face::PointDistanceBaseFunctor PDistFunct;
164
nearestF = unifGrid.GetClosest(PDistFunct,markerFunctor,(*vi).P(),maxDist,minDist,closestPt);
165
if (!nearestF) return false;
166
if (minDist == maxDist) return false;
169
if (i==0) (*nearestF).C() = Color4b::Green;
170
if (precedentF!=nearestF && precedentF!=NULL){ (*nearestF).C() = Color4b::Red;}
171
precedentF = nearestF;
174
//get gamma-ton direction over face
175
vcg::Point3f dustDirection = ((*nearestF).N().Normalize() ^ vcg::Point3f(0,-1,0)) ^ (*nearestF).N().Normalize();
177
float angle = vcg::Angle(dustDirection, vcg::Point3f(0,-1,0));
180
if (angle>1.309) //(5*M_PI)/12
183
speed = stepSize * vcg::math::Cos(angle);
185
dustDirection = dustDirection.Normalize();
186
dustDirection *= speed;
187
dustDirection += closestPt;
188
(*vi).P() = dustDirection;
195
/*!!! I don't understand why if i did't return MeshFilterInterface::FaceColoring all my function call
196
to FaceConstant (et simila) don't take effect over the mesh. I've read from Interface.c comment getClass is
197
only to decide where my plugin label is in Plugin submenu of meshlab menubar.*/
198
const MeshFilterInterface::FilterClass FilterDirt::getClass(QAction *)
200
return MeshFilterInterface::FaceColoring;
67
QString FilterDirt::filterName(FilterIDType filterId) const
71
return QString("Dust Accumulation");
74
case FP_CLOUD_MOVEMENT:
76
return QString("Points Cloud Movement");
80
assert(0); return QString("error");
86
QString FilterDirt::filterInfo(FilterIDType filterId) const
90
return QString("Simulate dust accumulation over the mesh");
93
case FP_CLOUD_MOVEMENT:{
94
return QString("Simulate the movement of a points cloud over a mesh");
98
assert(0); return QString("error");
103
void FilterDirt::initParameterSet(QAction* filter,MeshDocument &md, RichParameterSet &par){
109
MeshModel* m=md.getMesh(0);
111
par.addParam(new RichPoint3f("dust_dir",Point3f(0,1,0),"Direction","Direction of the dust source"));
112
par.addParam(new RichInt("nparticles",3,"particles","Max Number of Dust Particles to Generate Per Face"));
113
par.addParam(new RichFloat("slippiness",1,"s","The surface slippines"));
114
par.addParam(new RichFloat("adhesion",0.2,"k","Factor to model the general adhesion"));
115
par.addParam(new RichBool("draw_texture",false,"Draw Dust",""));
116
par.addParam(new RichBool("colorize_mesh",false,"Map to Color",""));
121
case FP_CLOUD_MOVEMENT:{
123
float max_value=md.mm()->cm.bbox.Diag();
124
par.addParam(new RichPoint3f("force_dir",Point3f(0,-1,0),"force","Direction of the force acting on the points cloud"));
125
par.addParam(new RichAbsPerc("s_length",max_value*perc,0,max_value,"Movement Length",""));
126
par.addParam(new RichFloat("velocity",0,"v","Initial velocity of the particle"));
127
par.addParam(new RichFloat("mass",1,"m","Mass of the particle"));
128
par.addParam(new RichBool("colorize_mesh",false,"Map to Color",""));
138
int FilterDirt::getRequirements(QAction */*action*/)
140
return MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTCOLOR |MeshModel::MM_FACECOLOR;
143
bool FilterDirt::applyFilter(QAction *filter, MeshDocument &md, RichParameterSet &par, vcg::CallBackPos *cb){
150
Point3f dir=par.getPoint3f("dust_dir");
151
float s=par.getFloat("slippiness");
152
float k=par.getFloat("adhesion");
153
bool draw=par.getBool("draw_texture");
154
bool colorize=par.getBool("colorize_mesh");
155
int n_p=par.getInt("nparticles");
157
MeshModel* currMM=md.mm();
159
if (currMM->cm.fn==0) {
160
errorMessage = "This filter requires a mesh with some faces, it does not work on PointSet";
164
if(draw && !currMM->cm.HasPerWedgeTexCoord()){
165
errorMessage = "Current Mesh does not have per Wedge Tex Coordinates";
169
vector<Point3f> dust_points;
170
vector<Particle<CMeshO> > dust_particles;
176
ComputeNormalDustAmount(currMM,dir,k,s);
177
ComputeSurfaceExposure(currMM,1,1);
178
GenerateParticles(currMM,dust_points,dust_particles,n_p,0.6);
181
MeshModel* dmm=md.addNewMesh("","dust_mesh");
184
tri::Allocator<CMeshO>::AddVertices(dmm->cm,dust_points.size());
185
CMeshO::PerVertexAttributeHandle<Particle<CMeshO> > ph= tri::Allocator<CMeshO>::AddPerVertexAttribute<Particle<CMeshO> > (dmm->cm,std::string("ParticleInfo"));
186
CMeshO::VertexIterator vi;
187
vector<Point3f>::iterator dvi=dust_points.begin();
188
std::vector< Particle<CMeshO> >::iterator dpi=dust_particles.begin();
190
for(vi=dmm->cm.vert.begin();vi!=dmm->cm.vert.end();++vi){
197
if(draw) DrawDust(currMM,dmm);
198
if(colorize) ColorizeMesh(currMM);
203
case FP_CLOUD_MOVEMENT:{
205
errorMessage="This filter requires two mesh";
209
MeshModel* base_mesh=md.getMesh(0);
210
if(base_mesh->cm.fn==0){
211
errorMessage="The filter requires that the first mesh has some faces";
215
MeshModel* cloud_mesh=md.getMesh(1);
216
if(cloud_mesh->cm.fn!=0){
217
errorMessage="The filter requires that the second mesh is a Point Set";
222
Point3f dir=par.getPoint3f("force_dir");;
223
float l =par.getAbsPerc("s_length");
224
float v=par.getFloat("velocity");
225
float m=par.getFloat("mass");
226
bool colorize=par.getBool("colorize_mesh");
227
if(!HasPerVertexAttribute(cloud_mesh->cm,"ParticleInfo")){
228
prepareMesh(base_mesh);
229
//Associate every point to a mesh and a Particle to every point
230
associateParticles(base_mesh,cloud_mesh,m,v);
234
MoveCloudMeshForward(cloud_mesh,dir,l,1,2);
236
if(colorize) ColorizeMesh(base_mesh);
251
int FilterDirt::postCondition( QAction *a) const
254
case FP_DIRT : return MeshModel::MM_UNKNOWN;
255
case FP_CLOUD_MOVEMENT : return MeshModel::MM_UNKNOWN;
259
return MeshModel::MM_NONE;
263
MeshFilterInterface::FilterClass FilterDirt::getClass(QAction *filter)
266
case FP_DIRT:return MeshFilterInterface::Sampling;
267
case FP_CLOUD_MOVEMENT:return MeshFilterInterface::Remeshing;
204
275
Q_EXPORT_PLUGIN(FilterDirt)