From d959e7f63a6ff090ad5cc56d670fdcdd256f42df Mon Sep 17 00:00:00 2001 From: Paolo Cignoni cignoni Date: Wed, 6 Oct 2010 00:24:27 +0000 Subject: [PATCH] improved movement of particles on the Surface more realistic generation of dust mesh implemented in dirt_utils.h deleted dustsampler.h --- src/fgt/filter_dirt/dirt_utils.h | 279 +++++++++++++++++++--------- src/fgt/filter_dirt/dustparticle.h | 14 +- src/fgt/filter_dirt/filter_dirt.cpp | 139 +++++--------- src/fgt/filter_dirt/filter_dirt.h | 2 +- src/fgt/filter_dirt/filter_dirt.pro | 4 +- 5 files changed, 246 insertions(+), 192 deletions(-) diff --git a/src/fgt/filter_dirt/dirt_utils.h b/src/fgt/filter_dirt/dirt_utils.h index 564538f25..f7b1d7845 100644 --- a/src/fgt/filter_dirt/dirt_utils.h +++ b/src/fgt/filter_dirt/dirt_utils.h @@ -24,8 +24,8 @@ #define DIRT_UTILS_H //Include Files +#include #include - #include #include #include @@ -34,25 +34,33 @@ #include #include #include - - +#include "dustparticle.h" /* @description Simulate the movement of a point, affected by a force "dir" on a face. - @parameter CMeshO::CoordType p - coordinates of the point - @parameter CMeshO::FaceType face - pointer to the face - @parameter CmeshO;;CoordType dir + @param CoordType p - coordinates of the point + @param CoordType v - velocity of the particle + @param float m - mass of the particle + @param FaceType face - pointer to the face + @param CoordType dir - direction of the force + @param float t - time step + @return new coordinates of the point */ -CMeshO::CoordType StepForward(CMeshO::CoordType p, CMeshO::FacePointer &face, CMeshO::CoordType dir,float t=1){ +CMeshO::CoordType StepForward(CMeshO::CoordType p, + CMeshO::CoordType v, + float m, + CMeshO::FacePointer &face, + CMeshO::CoordType dir, + float t=1){ //int t=1; Point3 new_pos; - Point3 n= face->N(); + Point3 n= face->cN(); float a=n[0]*dir[0]+n[1]*dir[1]+n[2]*dir[2]; - //if(a<0.01 && a>-0.01 ) return p; + Point3 f; //Calcolo le componenti della forza lungo il piano @@ -62,51 +70,72 @@ CMeshO::CoordType StepForward(CMeshO::CoordType p, CMeshO::FacePointer &face, CM - new_pos[0]=p[0]+0.5*f[0]*t*t; - new_pos[1]=p[1]+0.5*f[1]*t*t; - new_pos[2]=p[2]+0.5*f[2]*t*t; + new_pos[0]=p[0]+v[0]*t+0.5*(f[0]/m)*pow(t,2); + new_pos[1]=p[1]+v[1]*t+0.5*(f[1]/m)*pow(t,2); + new_pos[2]=p[2]+v[2]*t+0.5*(f[2]/m)*pow(t,2); return new_pos; }; -void DrawDirt(MeshDocument &md,std::vector &dp){ -//TODO +void DrawDirt(MeshModel &m/*,std::vector &dp*/){ + + float base_color=255; + float s_color; + std::pair minmax = tri::Stat::ComputePerFaceQualityMinMax(m.cm); + CMeshO::FaceIterator fi; + + for(fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi) + { + if(fi->Q()>0.5){ + + s_color=(1-(*fi).Q())*base_color; + (*fi).C()=Color4b(s_color, s_color, s_color, 0); + }else{ + (*fi).C()=Color4b(255,255,255,255); + } + } + + + // (*fi).C().ColorRamp(minmax.first,minmax.second,(*fi).Q()); + }; -bool ComputeIntersection(CMeshO::CoordType p1, - CMeshO::CoordType p2, - CMeshO::FacePointer &f, - CMeshO::CoordType &int_point, - CMeshO::FacePointer &new_f){ +/* +@description Compute the intersection of the segment from p1 to p2 and the face f + +@param CoordType p1 - position of the first point +@param Coordtype p2 - position of the second poin +@param Facepointer f - pointer to the face +@param CoordType int_point - intersection point this is a return parameter for the function. +@param FacePointer face - pointer to the new face +@return true if there is an intersection + +*/ + + +bool ComputeIntersection(CMeshO::CoordType p1,CMeshO::CoordType p2,CMeshO::FacePointer &f,CMeshO::CoordType &int_point,CMeshO::FacePointer &new_f) +{ + CMeshO::CoordType n=f->N(); - //(*f).C()=Color4b::Blue; int max_c; - float n0=math::Abs(n[0]); + /*float n0=math::Abs(n[0]); float n1=math::Abs(n[1]); float n2=math::Abs(n[2]); - - if(n0>n1){ - if(n0>n2) max_c=0; - else max_c=2; - }else{ - if(n1>n2) max_c=1; - else max_c=2; - } - - /* - if(n0>n1){ - if(n0>n2) max_c=0; - else max_c=2; - }else{ - if(n1>n2) max_c=1; - else max_c=2; - } */ - // CMeshO::CoordType int_point; + float n0=n[0]; + float n1=n[1]; + float n2=n[2]; + if(n0>n1){ + if(n0>n2) max_c=0; + else max_c=2; + }else{ + if(n1>n2) max_c=1; + else max_c=2; + } Point2f int_p; Segment2f seg; @@ -195,53 +224,25 @@ bool ComputeIntersection(CMeshO::CoordType p1, } } -/* - if(SegmentSegmentIntersection(line0,seg,int_p)){ - int_found=true; - edge=0; - }else{ - if(SegmentSegmentIntersection(line1,seg,int_p)){ - int_found=true; - edge=1; - }else{ - if(SegmentSegmentIntersection(line2,seg,int_p)){ - int_found=true; - edge=2; - } - } - - } - -*/ - - if(int_found){ - - - - - - - f->C()=Color4b::Red;//Debug - new_f=f->FFp(edge); - - + //f->C()=Color4b::Blue; //Debugging + new_f=f->FFp(edge); + //new_f->C()=Color4b::Green;//Debugging switch(max_c){ - - case 0:{ + case 0:{ int_point[0]=(n[0]*fv0[0]-n[1]*(int_p[0]-fv0[1])-n[2]*(int_p[1]-fv0[2]))/n[0]; int_point[1]=int_p[0]; int_point[2]=int_p[1]; break; - } - case 1:{ + } + case 1:{ int_point[0]=int_p[0]; int_point[1]=(n[1]*fv0[1]-n[0]*(int_p[0]-fv0[0])-n[2]*(int_p[1]-fv0[2]))/n[1]; int_point[2]=int_p[1]; break; - } - case 2:{ + } + case 2:{ int_point[0]=int_p[0]; int_point[1]=int_p[1]; int_point[2]=(n[2]*fv0[2]-n[0]*(int_p[0]-fv0[0])-n[1]*(int_p[1]-fv0[1]))/n[2]; @@ -253,39 +254,139 @@ bool ComputeIntersection(CMeshO::CoordType p1, } - - return int_found; }; -bool IsOnFace(CMeshO::CoordType &p, CMeshO::FacePointer &f){ + + +CMeshO::CoordType RandomBaricentric(){ + CMeshO::CoordType interp; + + static math::MarsenneTwisterRNG rnd; + interp[1] = rnd.generate01(); + interp[2] = rnd.generate01(); + if(interp[1] + interp[2] > 1.0) + { + interp[1] = 1.0 - interp[1]; + interp[2] = 1.0 - interp[2]; + } + + assert(interp[1] + interp[2] <= 1.0); + interp[0]=1.0-(interp[1] + interp[2]); + return interp; + }; + +/* +@description Compute the Normal Dust Amount Function per face of a Mesh m + +@param m MeshModel +@param u CoordType dust direction +@param k float +@param s float +*/ +bool ComputeNormalDustAmount(MeshModel* m,CMeshO::CoordType u,float k,float s){ + + //Verify if FaceQualty is enabled + CMeshO::FaceIterator fi; + float d; + for(fi=m->cm.face.begin();fi!=m->cm.face.end();++fi){ + d=k/s+(1+k/s)*pow(fi->N().dot(u),s); + fi->Q()=d; + } + return true; +}; + +/* +@description This function compute the Surface Exposure per face of a Mesh m + + +*/ +float ComputeSurfaceExposure(MeshModel* m){ + return 0.0f; +}; + +void CreateDustTexture(MeshModel* m){ + QString textName="dust_texture"; + QString fileName(m->fullName()); + fileName = fileName.left(std::max(fileName.lastIndexOf('\\'),fileName.lastIndexOf('/'))+1).append(textName); + QFile textFile(fileName); + QImage img(640, 640, QImage::Format_RGB32); + img.fill(qRgb(0,0,0)); // black + img.save(fileName,"jpg"); + m->cm.textures.clear(); + m->cm.textures.push_back(textName.toStdString()); + +} + +bool GenerateDustParticles(MeshModel* m,std::vector &cpv,std::vector > &dpv,int d,float threshold){ + + CMeshO::FaceIterator fi; + CMeshO::CoordType p; + cpv.clear(); + dpv.clear(); + //bool added=false; //debugging + + for(fi=m->cm.face.begin();fi!=m->cm.face.end();++fi){ + if(fi->Q()>threshold){ + for(int i=0;i<(int)d*fi->Q()/* && !added*/;i++){ + //added=true; + p=RandomBaricentric(); + CMeshO::CoordType n_p; + n_p[0]=fi->P(0)[0]*p[0]+fi->P(1)[0]*p[1]+fi->P(2)[0]*p[2]; + n_p[1]=fi->P(0)[1]*p[0]+fi->P(1)[1]*p[1]+fi->P(2)[1]*p[2]; + n_p[2]=fi->P(0)[2]*p[0]+fi->P(1)[2]*p[1]+fi->P(2)[2]*p[2]; + //cpv.push_back(fi->P(0)*p[0]+fi->P(1)*p[1]+fi->P(2)*p[2]); + cpv.push_back(n_p); + DustParticle part; + part.face=&(*fi); + part.bar_coord=p; + dpv.push_back(part); + } + } + } + + +return true; +}; + +/* +@description + +@param +@param +*/ +bool IsOnFace(CMeshO::CoordType &p, CMeshO::FacePointer f){ CMeshO::CoordType b; CMeshO::CoordType p0=f->P(0); CMeshO::CoordType p1=f->P(1); CMeshO::CoordType p2=f->P(2); + //x - float A=p0[0]-p2[0]; - float B=p1[0]-p2[0]; - float C=p2[0]-p[0]; + double A=p0[0]-p2[0]; + double B=p1[0]-p2[0]; + double C=p2[0]-p[0]; //y - float D=p0[1]-p2[1]; - float E=p1[1]-p2[1]; - float F=p2[1]-p[1]; + double D=p0[1]-p2[1]; + double E=p1[1]-p2[1]; + double F=p2[1]-p[1]; //z - float G=p0[1]-p2[1]; - float H=p1[1]-p2[1]; - float I=p2[1]-p[1]; + double G=p0[2]-p2[2]; + double H=p1[2]-p2[2]; + double I=p2[2]-p[2]; b[0]=( B*(F+I)-C*(E+H))/( A*(E+H)-B*(D+G) ); b[1]=( A*(F+I)-C*(D+G))/( B*(D+G)- A*(E+H) ); b[2]=1.0-b[0]-b[1]; - if(b[0]<0 || b[1]<0 || b[2]<0) return false; + if(b[0]<0 || b[1]<0 || b[2]<0) return false; - return true; + return true; }; + + + #endif // DIRT_UTILS_H diff --git a/src/fgt/filter_dirt/dustparticle.h b/src/fgt/filter_dirt/dustparticle.h index 02d98279f..e2c6d4684 100644 --- a/src/fgt/filter_dirt/dustparticle.h +++ b/src/fgt/filter_dirt/dustparticle.h @@ -28,7 +28,6 @@ #include #include #include -#include "dirt_utils.h" template @@ -39,17 +38,24 @@ class DustParticle{ typedef typename MeshType::FacePointer FacePointer; public: DustParticle(){ - mass=1; + mass=1.0f; + speed[0]=0.0f; + speed[1]=0.0f; + speed[2]=0.0f; }; + DustParticle(float m,CoordType v){ + mass=m; + speed=v; + }; ~DustParticle(){}; public: FacePointer face; - CoordType bar_coord; + CoordType bar_coord;/*To delete?*/ float mass; - float speed;/*to delete?*/ + CoordType speed; float ad_coeff;/*Adhesion Coefficient*/ diff --git a/src/fgt/filter_dirt/filter_dirt.cpp b/src/fgt/filter_dirt/filter_dirt.cpp index fb5b392f8..73cea65fa 100644 --- a/src/fgt/filter_dirt/filter_dirt.cpp +++ b/src/fgt/filter_dirt/filter_dirt.cpp @@ -25,7 +25,7 @@ #include #include "filter_dirt.h" #include "dustparticle.h" -#include "dustsampler.h" +//#include "dustsampler.h" #include "dirt_utils.h" @@ -78,6 +78,7 @@ QString FilterDirt::filterName(FilterIDType filterId) const break; } } + QString FilterDirt::filterInfo(FilterIDType filterId) const { switch (filterId) { @@ -91,9 +92,18 @@ QString FilterDirt::filterInfo(FilterIDType filterId) const } void FilterDirt::initParameterSet(QAction* filter,MeshDocument &md, RichParameterSet &par){ - par.addParam(new RichInt("nparticles",1000,"Number of Dust Particles","Number of Dust Particles to Generate")); - //par.addParam(new RichDynamicFloat("step",0,0,10,"Steps","Steps of simulation")); + + + par.addParam(new RichFloat("dir_x",0.0,"x","x direction of dust source")); + par.addParam(new RichFloat("dir_y",0.0,"y","y direction of dust source")); + par.addParam(new RichFloat("dir_z",0.0,"z","z direction of dust source")); + par.addParam(new RichInt("nparticles",10,"particles","Max Number of Dust Particles to Generate Per Face")); + par.addParam(new RichFloat("slippiness",1,"s","The surface slippines")); + par.addParam(new RichFloat("adhesion",0.2,"k","Factor to model the general adhesion")); + par.addParam(new RichBool("mtc",false,"Map To Colors","")); + par.addParam(new RichBool("gt",false,"Generate Texture","")); + //par.addParam(new RichDynamicFloat("step",0,0,10,"Steps","Steps of simulation")); return; } @@ -106,53 +116,48 @@ bool FilterDirt::applyFilter(QAction *filter, MeshDocument &md, RichParameterSet { - if(md.size()>=2){//This is temporary just to try new steps of simulation + if(md.size()>=2){//This is temporary, just to try new steps of simulation MeshModel* dmesh=md.getMesh("Dust Mesh"); Point3f dir; Point3f new_bar_coords; dir[0]=0; - dir[1]=0; - dir[2]=0.5; + dir[1]=-1; + dir[2]=0; if(dmesh!=0){ CMeshO::VertexIterator vi;//= dmesh->cm.vert.begin(); CMeshO::PerVertexAttributeHandle > pi = tri::Allocator::GetPerVertexAttribute >(dmesh->cm,"ParticleInfo"); CMeshO::CoordType new_pos; CMeshO::CoordType int_p; + CMeshO::FacePointer pre_face; CMeshO::FacePointer new_f; bool stop_movement=false; for(vi=dmesh->cm.vert.begin();vi!=dmesh->cm.vert.end();++vi){ stop_movement=false; - new_pos=StepForward((*vi).P(),pi[vi].face,dir); + pre_face=pi[vi].face; + new_pos=StepForward((*vi).P(),pi[vi].speed,pi[vi].mass,pi[vi].face,dir); while(!stop_movement){ if(!IsOnFace(new_pos,pi[vi].face)){ - //if(ComputeIntersection((*vi).P(),new_pos,pi[vi].face,int_p,new_f)){ + //if(ComputeIntersection((*vi).P(),new_pos,pi[vi].face,int_p,new_f)) ComputeIntersection((*vi).P(),new_pos,pi[vi].face,int_p,new_f); - pi[vi].face=new_f; Segment3f s1=Segment3f((*vi).P(),new_pos); Segment3f s2=Segment3f((*vi).P(),int_p); - float t=s2.Length()/s1.Length(); new_pos=int_p; (*vi).P()=new_pos; - (*pi[vi].face).C()=Color4b::Blue;//Debugging - new_pos=StepForward((*vi).P(),pi[vi].face,dir,t); - - /*if(!IsOnFace(new_pos,pi[vi].face)) - { { - (*pi[vi].face).C()=Color4b::Green;//Debugging - stop_movement=true; - (*vi).P()=new_pos; - }*/ -// } + if(pre_face!=new_f) + { + float t=s2.Length()/s1.Length(); + pre_face=new_f; + new_pos=StepForward((*vi).P(),pi[vi].speed,pi[vi].mass,pi[vi].face,dir,t); + } + else stop_movement=true; }else{ - //The new position is on the same face - (*pi[vi].face).C()=Color4b::Green;//Debugging - stop_movement=true; + stop_movement=true; (*vi).P()=new_pos; } @@ -162,28 +167,31 @@ bool FilterDirt::applyFilter(QAction *filter, MeshDocument &md, RichParameterSet } } }else{ - //First Application + Point3f dir; + dir[0]=par.getFloat("dir_x"); + dir[1]=par.getFloat("dir_y"); + dir[2]=par.getFloat("dir_z"); + vector dustVertexVec; vector > dustParticleVec; - - DustSampler ts(dustVertexVec,dustParticleVec); MeshModel* currMM=md.mm(); + if (currMM->cm.fn==0) { errorMessage = "This filter requires a mesh with some faces,
it does not work on PointSet"; return false; } std::string func_d = "ny"; - currMM->updateDataMask(MeshModel::MM_FACEFACETOPO); currMM->updateDataMask(MeshModel::MM_FACEMARK); currMM->updateDataMask(MeshModel::MM_FACECOLOR); currMM->updateDataMask(MeshModel::MM_VERTQUALITY); + currMM->updateDataMask(MeshModel::MM_FACEQUALITY); + //currMM->updateDataMask(MeshModel::MM_WEDGTEXCOORD); tri::UnMarkAll(currMM->cm); //clean Mesh - tri::Allocator::CompactFaceVector(currMM->cm); tri::Clean::RemoveUnreferencedVertex(currMM->cm); tri::Clean::RemoveDuplicateVertex(currMM->cm); @@ -197,28 +205,15 @@ bool FilterDirt::applyFilter(QAction *filter, MeshDocument &md, RichParameterSet tri::UpdateNormals::PerFaceNormalized(currMM->cm); tri::UpdateFlags::FaceProjection(currMM->cm); - Parser p; - - - setPerVertexVariables(p); - p.SetExpr(func_d); - - CMeshO::VertexIterator vi; - - for(vi=currMM->cm.vert.begin();vi!=currMM->cm.vert.end();++vi) - { - setAttributes(vi,currMM->cm); - try { - (*vi).Q() = p.Eval(); - } catch(Parser::exception_type &e) { - errorMessage = e.GetMsg().c_str(); - return false; - } + //Initialize quality for face + CMeshO::FaceIterator fIter; + for(fIter=currMM->cm.face.begin();fIter!=currMM->cm.face.end();++fIter){ + fIter->Q()=0; } - tri::SurfaceSampling >::Montecarlo(currMM->cm,ts,par.getInt("nparticles")); - - //dmm -> Dust Mesh Model + ComputeNormalDustAmount(currMM,dir,par.getFloat("adhesion"),par.getFloat("slippiness")); + GenerateDustParticles(currMM,dustVertexVec,dustParticleVec,par.getInt("nparticles"),0.6); + //dmm-> Dust Mesh Model MeshModel* dmm=md.addNewMesh("Dust Mesh"); dmm->cm.Clear(); @@ -226,20 +221,17 @@ bool FilterDirt::applyFilter(QAction *filter, MeshDocument &md, RichParameterSet CMeshO::PerVertexAttributeHandle > ph= tri::Allocator::AddPerVertexAttribute > (dmm->cm,std::string("ParticleInfo")); - CMeshO::VertexIterator vIter=dmm->cm.vert.begin(); vector::iterator dvIter; std::vector< DustParticle >::iterator dpIter=dustParticleVec.begin(); for(dvIter=dustVertexVec.begin();dvIter!=dustVertexVec.end();++dvIter){ (*vIter).P()=CMeshO::CoordType ((*dvIter)[0],(*dvIter)[1],(*dvIter)[2]); - ph[vIter]=(*dpIter); ++dpIter; ++vIter; } } - return true; } @@ -248,52 +240,7 @@ MeshFilterInterface::FilterClass FilterDirt::getClass(QAction *) return MeshFilterInterface::VertexColoring; } -void FilterDirt::setPerVertexVariables(Parser &p) -{ - p.DefineVar("x", &x); - p.DefineVar("y", &y); - p.DefineVar("z", &z); - p.DefineVar("nx", &nx); - p.DefineVar("ny", &ny); - p.DefineVar("nz", &nz); - p.DefineVar("r", &r); - p.DefineVar("g", &g); - p.DefineVar("b", &b); - p.DefineVar("q", &q); - p.DefineVar("vi",&v); - p.DefineVar("rad",&rad); - // define var for user-defined attributes (if any exists) - // if vector is empty, code won't be executed - for(int i = 0; i < (int) v_attrNames.size(); i++) - p.DefineVar(v_attrNames[i],&v_attrValue[i]); -} -void FilterDirt::setAttributes(CMeshO::VertexIterator &vi, CMeshO &m) -{ - x = (*vi).P()[0]; // coord x - y = (*vi).P()[1]; // coord y - z = (*vi).P()[2]; // coord z - - nx = (*vi).N()[0]; // normal coord x - ny = (*vi).N()[1]; // normal coord y - nz = (*vi).N()[2]; // normal coord z - - r = (*vi).C()[0]; // color R - g = (*vi).C()[1]; // color G - b = (*vi).C()[2]; // color B - - q = (*vi).Q(); // quality - - if(tri::HasPerVertexRadius(m)) rad = (*vi).R(); - else rad=0; - - v = vi - m.vert.begin(); // zero based index of current vertex - - // if user-defined attributes exist (vector is not empty) - // set variables to explicit value obtained through attribute's handler - for(int i = 0; i < (int) v_attrValue.size(); i++) - v_attrValue[i] = vhandlers[i][vi]; -} Q_EXPORT_PLUGIN(FilterDirt) diff --git a/src/fgt/filter_dirt/filter_dirt.h b/src/fgt/filter_dirt/filter_dirt.h index 9444f6063..9d0659416 100644 --- a/src/fgt/filter_dirt/filter_dirt.h +++ b/src/fgt/filter_dirt/filter_dirt.h @@ -50,7 +50,7 @@ class FilterDirt : public QObject, public MeshFilterInterface std::vector v_attrNames; std::vector v_attrValue; //std::vector f_attrNames; - //std::vector f_attrValue; + //std:: vector f_attrValue; std::vector > vhandlers; //std::vector > fhandlers; diff --git a/src/fgt/filter_dirt/filter_dirt.pro b/src/fgt/filter_dirt/filter_dirt.pro index 21f4b3ed1..51643eae9 100644 --- a/src/fgt/filter_dirt/filter_dirt.pro +++ b/src/fgt/filter_dirt/filter_dirt.pro @@ -1,8 +1,8 @@ include (../../shared.pri) HEADERS = filter_dirt.h \ - dirt_utils.h \ dustparticle.h \ - dustsampler.h \ + dirt_utils.h \ +# dustsampler.h \ $$VCGDIR/vcg/complex/trimesh/point_sampling.h SOURCES = filter_dirt.cpp