/*************************************************************************** File: SimSphere.cpp Created: 01/22/02 Author: Maxim Garber Computer Science Department University of North Carolina - Chapel Hill garber@cs.unc.edu DescriptioN: Projectile sphere which interacts with cloth simulation ----------------------------------------------------------------------------. Copyright 2002 Maxim Garber *****************************************************************************/ #include "SimSphere.h" #include #include #include // openGL headers #include #include "GL\gl.h" #include "GL\glu.h" #include "GL\glut.h" /***************************************************************************** FUNCTION : SimSphere DESCRIPTION: Initializes the sphere *****************************************************************************/ SimSphere::SimSphere(char* fileName) { // initialize parameters Set3fv(_center, 0.0f,0.0f,0.0f); Set3fv(_prevCenter, 0.0f,0.0f,0.0f); Set3fv(_force, 0.0f,0.0f,0.0f); _dampingFactor = 0.95f; Set3fv(_gravity, 0.0f, -9.8f, 0.0f); _numIterations = 2; _timeOnTheGround = 0.0f; _color[0] = 1; _color[1] = 1; _color[2] = 1; FILE* fp = fopen(fileName,"r"); if (fp==NULL) { printf("ERROR: unable to open ObjFile [%s]!\n",fileName); exit(1); } char string[50]; /////////////////////////////////////////////////////////////////////////// // Read Parameters fscanf(fp, "%s", &string); if(strcmp(string, "[sphere_parameters]") != 0) { printf("ERROR: invalid ObjFile format [%s]!\n",fileName); exit(1); } // read next attribute fscanf(fp, "%s", &string); while(strcmp(string, "[end]") != 0) { if(strcmp(string, "center:") == 0) for(unsigned int i = 0; i < 3; i++) fscanf(fp, "%f", &_center[i]); if(strcmp(string, "velocity:") == 0) { float velocity[3]; for(unsigned int i = 0; i < 3; i++) fscanf(fp, "%f", &velocity[i]); Subtract3fv(_prevCenter, _center, velocity); } if(strcmp(string, "radius:") == 0) fscanf(fp, "%f", &_radius); if(strcmp(string, "draw_radius:") == 0) fscanf(fp, "%f", &_drawRadius); // color if(strcmp(string, "color:") == 0) { unsigned int HexColor, RedMask=0xff0000, GreenMask=0xff00, BlueMask=0xff; fscanf(fp,"%x",&HexColor); _color[0] = (unsigned char)((HexColor & RedMask) >> 16); _color[1] = (unsigned char)((HexColor & GreenMask) >> 8); _color[2] = (unsigned char)(HexColor & BlueMask); } if(strcmp(string, "max_ground_time:") == 0) fscanf(fp, "%f", &_maxTimeOnGround); // physical simulation if(strcmp(string, "inverse_mass:") == 0) fscanf(fp, "%f", &_inverseMass); if(strcmp(string, "damping_factor:") == 0) fscanf(fp, "%f", &_dampingFactor); if(strcmp(string, "gravity:") == 0) for(unsigned int i = 0; i < 3; i++) fscanf(fp, "%f", &_gravity[i]); if(strcmp(string, "num_iterations:") == 0) fscanf(fp, "%d", &_numIterations); // read next attribute fscanf(fp, "%s", &string); } } /***************************************************************************** FUNCTION : ~SimSphere DESCRIPTION: Deletes all allocated memory *****************************************************************************/ SimSphere::~SimSphere(){} void SimSphere::Launch(ProjectileLaunchParams params) { // copy launch position Copy3fv(_center, params.position); // compute velocity unit vector float velocity[3]; velocity[0] = cosf(params.azimuth)*cosf(params.elevation); velocity[1] = sinf(params.elevation); velocity[2] = sinf(params.azimuth)*cosf(params.elevation); // compute launch muzzle velocity // - assume a 1m muzzle with constant force applied along its length // - the force is 10000N per mass of powder // - equation for final velocity is v = (2*Force/mass * muzzleLength)^0.5 float velocityMagnitude = sqrtf(2*(10*params.powderMass)*_inverseMass); // compute complete launch velicity magnitude ScalarMult3fv(velocity, velocity, velocityMagnitude); // set previous center to be the center minus the velocity Subtract3fv(_prevCenter, _center, velocity); // set external forces to zero Set3fv(_force, 0.0f, 0.0f, 0.0f); } /***************************************************************************** FUNCTION : Draw DESCRIPTION: Draws the sphere *****************************************************************************/ void SimSphere::Draw() const { //draw sphere glPushMatrix(); glColor3ubv(_color); glTranslatef(_center[0], _center[1], _center[2]); glutSolidSphere(_drawRadius, 20, 20); glPopMatrix(); // draw shadow glPushMatrix(); glColor4f(0.0f, 0.0f, 0.0f, 0.5); glScalef(1.0f, 0.01/_drawRadius, 1.0f); glTranslatef(_center[0], 0.01, _center[2]); glutSolidSphere(_drawRadius, 10, 10); glPopMatrix(); } /***************************************************************************** FUNCTION : Update DESCRIPTION: Updates cloth control points for the elapsed timestep under all forces considered. *****************************************************************************/ void SimSphere::Update(float timeStep) { _timeStep = timeStep; if(_isFree) { _AccumulateForces(); _Integrate(); _SatisfyConstraints(); } } /***************************************************************************** FUNCTION : _initializeSimulation DESCRIPTION: Initilializes simulation values; *****************************************************************************/ void SimSphere::_InitializeSimulation() { _timeStep = 0.0f; _dampingFactor = 0.95f; Set3fv(_gravity, 0.0f, -0.02f, 0.0f); _numIterations = 1; _isFree = 1; ClearForce(); } /***************************************************************************** FUNCTION : mAccumulateForces DESCRIPTION: Collects all forces acting on particles of cloth *****************************************************************************/ void SimSphere::_AccumulateForces() { Add3fv(_force, _force, _gravity); } /***************************************************************************** FUNCTION : _integrate DESCRIPTION: Uses Verlet integration to update cloth particle positions due to applied forces. applies the formula: x = (x - old_x)*damping + force*timesStep^2 *****************************************************************************/ void SimSphere::_Integrate() { float temp[3] = {_center[0], _center[1], _center[2]}; float force[3], velocity[3]; // integrate force to get new velocity ScalarMult3fv(force, _force, _timeStep*_timeStep); // compute velocity Subtract3fv (velocity, _center, _prevCenter ); ScalarMult3fv(velocity, velocity, _dampingFactor); // update new position Add3fv (_center, _center, velocity ); Add3fv (_center, _center, force ); Copy3fv (_prevCenter, temp ); ClearForce(); // check if ball is on the ground if(_center[1] - _drawRadius < 0.01) _timeOnTheGround += _timeStep; } /***************************************************************************** FUNCTION : mSatisfyConstraints DESCRIPTION: Uses Gauss-Siedel relaxation to satisfy constriants using a maximum number of iterations; *****************************************************************************/ void SimSphere::_SatisfyConstraints() { for(unsigned int iter = 0; iter < _numIterations; iter++) { /*************************************************************** Collision Detection ***************************************************************/ // collision with floor if(_center[1] < _drawRadius)_center[1] = _drawRadius; } }