improved movement of particles on the Surface

more realistic generation of dust mesh implemented in dirt_utils.h
deleted dustsampler.h
This commit is contained in:
Paolo Cignoni cignoni 2010-10-06 00:24:27 +00:00
parent 26fb620ec0
commit d959e7f63a
5 changed files with 246 additions and 192 deletions

View File

@ -24,8 +24,8 @@
#define DIRT_UTILS_H
//Include Files
#include <vcg/complex/trimesh/point_sampling.h>
#include <math.h>
#include <common/meshmodel.h>
#include <common/interfaces.h>
#include<vector>
@ -34,25 +34,33 @@
#include<vcg/complex/trimesh/base.h>
#include <vcg/space/point3.h>
#include <vcg/space/intersection2.h>
#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<float> new_pos;
Point3<float> n= face->N();
Point3<float> 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<float> 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<Point3f> &dp){
//TODO
void DrawDirt(MeshModel &m/*,std::vector<Point3f> &dp*/){
float base_color=255;
float s_color;
std::pair<float,float> minmax = tri::Stat<CMeshO>::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<int>(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<CMeshO::CoordType> &cpv,std::vector<DustParticle <CMeshO> > &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<CMeshO> 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

View File

@ -28,7 +28,6 @@
#include<vcg/simplex/vertex/base.h>
#include<vcg/simplex/face/base.h>
#include<vcg/complex/trimesh/base.h>
#include "dirt_utils.h"
template <class MeshType>
@ -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*/

View File

@ -25,7 +25,7 @@
#include <QtGui>
#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<DustParticle<CMeshO> > pi = tri::Allocator<CMeshO>::GetPerVertexAttribute<DustParticle<CMeshO> >(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<Point3f> dustVertexVec;
vector<DustParticle<CMeshO> > dustParticleVec;
DustSampler<CMeshO> ts(dustVertexVec,dustParticleVec);
MeshModel* currMM=md.mm();
if (currMM->cm.fn==0) {
errorMessage = "This filter requires a mesh with some faces,<br> 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<CMeshO>::CompactFaceVector(currMM->cm);
tri::Clean<CMeshO>::RemoveUnreferencedVertex(currMM->cm);
tri::Clean<CMeshO>::RemoveDuplicateVertex(currMM->cm);
@ -197,28 +205,15 @@ bool FilterDirt::applyFilter(QAction *filter, MeshDocument &md, RichParameterSet
tri::UpdateNormals<CMeshO>::PerFaceNormalized(currMM->cm);
tri::UpdateFlags<CMeshO>::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<CMeshO,DustSampler<CMeshO> >::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<DustParticle<CMeshO> > ph= tri::Allocator<CMeshO>::AddPerVertexAttribute<DustParticle<CMeshO> > (dmm->cm,std::string("ParticleInfo"));
CMeshO::VertexIterator vIter=dmm->cm.vert.begin();
vector<Point3f>::iterator dvIter;
std::vector< DustParticle<CMeshO> >::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)

View File

@ -50,7 +50,7 @@ class FilterDirt : public QObject, public MeshFilterInterface
std::vector<std::string> v_attrNames;
std::vector<double> v_attrValue;
//std::vector<std::string> f_attrNames;
//std::vector<double> f_attrValue;
//std:: vector<double> f_attrValue;
std::vector<CMeshO::PerVertexAttributeHandle<float> > vhandlers;
//std::vector<CMeshO::PerFaceAttributeHandle<float> > fhandlers;

View File

@ -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