#pragma once #ifdef _WIN32 #include #endif #include "ClothSim.h" #include "objLoader.h" #include "BSH.h" #include "MinSphere.h" #include "list.h" #include #include #include #include #include #include using namespace std; /* Some physics constants */ #define DAMPING 0.01 // how much to damp the cloth simulation each frame #define TIME_STEPSIZE2 0.35*0.35 // how large time step each particle takes each frame #define CONSTRAINT_ITERATIONS 15 // how many iterations of constraint satisfaction each frame (more is rigid, less is soft) static GLint ImageWidth=1280; static GLint ImageHeight=720; objLoader *objdata; BSH *bsh; /*********************************************************************************************************************************************/ float Vec3:: length() { return sqrt(f[0]*f[0]+f[1]*f[1]+f[2]*f[2]); } Vec3:: Vec3(float x, float y, float z) { f[0] =x; f[1] =y; f[2] =z; } Vec3:: Vec3(){} Vec3 Vec3:: normalized() { float l = length(); return Vec3(f[0]/l,f[1]/l,f[2]/l); } void Vec3:: operator+= (const Vec3 &v) { f[0]+=v.f[0]; f[1]+=v.f[1]; f[2]+=v.f[2]; } Vec3 Vec3:: operator/ (const float &a) { return Vec3(f[0]/a,f[1]/a,f[2]/a); } Vec3 Vec3:: operator- (const Vec3 &v) { return Vec3(f[0]-v.f[0],f[1]-v.f[1],f[2]-v.f[2]); } Vec3 Vec3:: operator+ (const Vec3 &v) { return Vec3(f[0]+v.f[0],f[1]+v.f[1],f[2]+v.f[2]); } Vec3 Vec3:: operator* (const float &a) { return Vec3(f[0]*a,f[1]*a,f[2]*a); } Vec3 Vec3:: operator-() { return Vec3(-f[0],-f[1],-f[2]); } Vec3 Vec3:: cross(const Vec3 &v) { return Vec3(f[1]*v.f[2] - f[2]*v.f[1], f[2]*v.f[0] - f[0]*v.f[2], f[0]*v.f[1] - f[1]*v.f[0]); } float Vec3:: dot(const Vec3 &v) { return f[0]*v.f[0] + f[1]*v.f[1] + f[2]*v.f[2]; } /* The particle class represents a particle of mass that can move around in 3D space*/ /**************************************************************************************************************************/ Particle ::Particle(Vec3 pos){ this->pos=pos; this->old_pos=pos; this->acceleration= Vec3(0,0,0); this->mass=1; this->movable=true; this->accumulated_normal=Vec3(0,0,0); this->state=-1; } Particle ::Particle(){} void Particle :: addForce(Vec3 f) { acceleration += f/mass; } /* This is one of the important methods, where the time is progressed a single step size (TIME_STEPSIZE) The method is called by Cloth.time_step() Given the equation "force = mass * acceleration" the next position is found through verlet integration*/ void Particle ::timeStep() { if(movable) { Vec3 temp = pos; pos = pos + (pos-old_pos)*(1.0-DAMPING) + acceleration*TIME_STEPSIZE2; old_pos = temp; acceleration = Vec3(0,0,0); // acceleration is reset since it HAS been translated into a change in position (and implicitely into velocity) } } Vec3& Particle ::getPos() {return pos;} void Particle :: resetAcceleration() {acceleration = Vec3(0,0,0);} void Particle :: offsetPos(const Vec3 v) { if(movable) pos += v;} void Particle :: makeUnmovable() {movable = false;} void Particle :: addToNormal(Vec3 normal) { accumulated_normal += normal.normalized(); } Vec3& Particle :: getNormal() { return accumulated_normal;} // notice, the normal is not unit length void Particle :: resetNormal() {accumulated_normal = Vec3(0,0,0);} /********************************************************************************************************************************/ Constraint:: Constraint(Particle *p1, Particle *p2) { this->p1=p1; this->p2=p2; Vec3 vec = p1->getPos()-p2->getPos(); rest_distance = vec.length(); } /* This is one of the important methods, where a single constraint between two particles p1 and p2 is solved the method is called by Cloth.time_step() many times per frame*/ void Constraint:: satisfyConstraint() { Vec3 p1_to_p2 = p2->getPos()-p1->getPos(); // vector from p1 to p2 float current_distance = p1_to_p2.length(); // current distance between p1 and p2 Vec3 correctionVector = p1_to_p2*(1 - rest_distance/current_distance); // The offset vector that could moves p1 into a distance of rest_distance to p2 Vec3 correctionVectorHalf = correctionVector*0.5; // Lets make it half that length, so that we can move BOTH p1 and p2. p1->offsetPos(correctionVectorHalf); // correctionVectorHalf is pointing from p1 to p2, so the length should move p1 half the length needed to satisfy the constraint. p2->offsetPos(-correctionVectorHalf); // we must move p2 the negative direction of correctionVectorHalf since it points from p2 to p1, and not p1 to p2. } /********************************************************************************************************************************/ ClothFace::ClothFace(Particle *p1, Particle *p2,Particle *p3, obj_face *c/*, int j*/){ this->p1=p1; this->p2=p2; this->p3= p3; // cout<<"in construct"<Clothfaces=c; } void Cloth:: getFaces(Particle *p1,Particle *p2,Particle *p3, int t[]){ obj_face *f= new obj_face; // int tab[4]={0,0,0,0}; /* for(int i=0;i<4;i++) {tab[i]=t[i]; f->normal_index[i]=0; f->texture_index[i]=0; }*/ f->material_index=f->vertex_count=0; for(int i=0;i<4;i++) {f->vertex_index[i]=t[i]; f->normal_index[i]=0; f->texture_index[i]=0; } Faces.push_back(ClothFace(p1,p2,p3,f)); //cout<<"Faces= "<getPos(); Vec3 pos2 = p2->getPos(); Vec3 pos3 = p3->getPos(); Vec3 v1 = pos2-pos1; Vec3 v2 = pos3-pos1; return v1.cross(v2); } /* A private method used by windForce() to calcualte the wind force for a single triangle defined by p1,p2,p3*/ void Cloth:: addWindForcesForTriangle(Particle *p1,Particle *p2,Particle *p3, const Vec3 direction) { Vec3 normal = calcTriangleNormal(p1,p2,p3); Vec3 d = normal.normalized(); Vec3 force = normal*(d.dot(direction)); p1->addForce(force); p2->addForce(force); p3->addForce(force); } /* A private method used by drawShaded(), that draws a single triangle p1,p2,p3 with a color*/ void Cloth:: drawTriangle(Particle *p1, Particle *p2, Particle *p3, const Vec3 color) { glColor3fv( (GLfloat*) &color ); glNormal3fv((GLfloat *) &(p1->getNormal().normalized() )); glVertex3fv((GLfloat *) &(p1->getPos() )); glNormal3fv((GLfloat *) &(p2->getNormal().normalized() )); glVertex3fv((GLfloat *) &(p2->getPos() )); glNormal3fv((GLfloat *) &(p3->getNormal().normalized() )); glVertex3fv((GLfloat *) &(p3->getPos() )); } /* This is a important constructor for the entire system of particles and constraints*/ Cloth:: Cloth(float width, float height, int num_particles_width, int num_particles_height,int Reslevel) { num_particles = num_particles_width * num_particles_height; this->num_particles_width=num_particles_width; this->num_particles_height=num_particles_height; particleActiveState.resize(num_particles_width*num_particles_width); //I am essentially using this vector as an array with room for num_particles_width*num_particles_height particles //vector *vec; vec vectr; //vector t ; t=new ListeSommet; //t->resize((num_particles_width* (Reslevel+1)-Reslevel)*(num_particles_width* (Reslevel+1)-Reslevel)); int i=0; // creating particles in a grid of particles from (0,0,0) to (width,-height,0) for(int x=0; xpush_back(S); } } /*Settinp up the resolution matrix */ int k=0; for(int i=0;i<=num_particles_width-1;i++) for(int j=0;j<=num_particles_height-1;j++) { MatResol1[i][j]=MatResol[i][j]=t->at(k++).index; } /* for(int i=0;i<=num_particles_width*2-1;i++) { printf("\n"); for(int j=0;j<=num_particles_height*2-1;j++) printf("%d -",MatResol[i][j]); }*/ k=0; /* Activate the particles of the first level*/ for(int i=0;ivertex_index[j] = Faces.at(i).Clothfaces->vertex_index[j]; } } this->Indexface=Clothface; obj_vector *listvertex= new obj_vector[vecteurtail]; ClothvertexList1Taille=0; int l=0; for (k=0;kFaces.clear(); /*for(int x = 0; x::iterator particle; //std::vector::iterator it; /*for(particle = particleActiveState.begin(); particle != particleActiveState.end(); particle++) { if((*particle).state==1) { Vec3 v = (*particle).getPos()-center; float l = v.length(); if ( v.length() < radius) // if the particle is inside the ball { (*particle).offsetPos(v.normalized()*(radius-l)); // project the particle to the surface of the ball } } }*/ int m=0; for (int k=0;k::iterator particle; for(int i=0;iload1(cloth1); bsh->BuidBSH(objdata,15,cloth1); bsh->SearchBSH(15); ball_time++; ball_pos.f[2] = cos(ball_time/50.0)*7; cloth1.addForce(Vec3(0,-0.2,0)*TIME_STEPSIZE2); // add gravity each frame, pointing down cloth1.windForce(Vec3(0.5,0,0.2)*TIME_STEPSIZE2); // generate some wind each frame cloth1.timeStep(); // calculate the particle positions of the next frame // drawing cloth1.ballCollision(ball_pos,ball_radius); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glDisable(GL_LIGHTING); // drawing some smooth shaded background - because I like it ;) glBegin(GL_POLYGON); glColor3f(0.8f,0.8f,1.0f); glVertex3f(-200.0f,-100.0f,-100.0f); glVertex3f(200.0f,-100.0f,-100.0f); glColor3f(0.4f,0.4f,0.8f); glVertex3f(200.0f,100.0f,-100.0f); glVertex3f(-200.0f,100.0f,-100.0f); glEnd(); glEnable(GL_LIGHTING); glTranslatef(-6.5,6,-9.0f); // move camera out and center on the cloth glRotatef(140,0,1,0); // rotate a bit to see the cloth from the side /////////////////////////////////////////// //draw the sphere hierarchy /*for (int i=0;ioutput->size();i++) { BSN *current=bsh->output->at(i); glPushMatrix(); glTranslatef(current->BS->center.x,current->BS->center.y,current->BS->center.z); glutWireSphere(current->BS->radius,40,40); glPopMatrix(); }*/ /////////////////////////////////////////// cloth1.drawShaded(); // finally draw the cloth with smooth shading glPushMatrix(); // to draw the ball we use glutSolidSphere, and need to draw the sphere at the position of the ball glTranslatef(ball_pos.f[0],ball_pos.f[1],ball_pos.f[2]); // hence the translation of the sphere onto the ball position glColor3f(0.4f,0.8f,0.5f); glutSolidSphere(ball_radius-0.1,50,50); // draw the ball, but with a slightly lower radius, otherwise we could get ugly visual artifacts of cloth penetrating the ball slightly glPopMatrix(); glutSwapBuffers(); cloth1.BSH_up_date();//updates the tree bsh->traverse(cloth1,bsh->root,ball_pos,ball_radius,3,TIME_STEPSIZE2); glutPostRedisplay(); } void reshape(int w, int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (h==0) gluPerspective(80,(float)w,1.0,5000.0); else gluPerspective (80,( float )w /( float )h,1.0,5000.0 ); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void keyboard( unsigned char key, int x, int y ) { switch ( key ) { case 27: exit ( 0 ); break; default: break; } } void arrow_keys( int a_keys, int x, int y ) { switch(a_keys) { case GLUT_KEY_UP: glutFullScreen(); break; case GLUT_KEY_DOWN: glutReshapeWindow (1280, 720 ); break; default: break; } } int main ( int argc, char** argv ) { glutInit( &argc, argv ); glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH ); glutInitWindowSize(ImageWidth, ImageHeight ); glutCreateWindow( "Cloth Simulation" ); init(); //cloth1.getFaces();// Here we build the faces of the cloth, in the vector Faces. objdata = new objLoader(); bsh=new BSH(); /*objdata->load1(cloth1); bsh=new BSH(); bsh->BuidBSH(objdata,6); bsh->SearchBSH(6); */ glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutSpecialFunc(arrow_keys); glutMainLoop(); }