Выбрать главу

// While Time Step Not Over

while (RestTime>ZERO) {

 lamda=10000; // Initialize To Very Large Value

 // For All The Balls Find Closest Intersection Between Balls And Planes / Cylinders

 for (int i=0;i<NrOfBalls;i++) {

  // Compute New Position And Distance

  OldPos[i]=ArrayPos[i];

  TVector::unit(ArrayVel[i],uveloc);

  ArrayPos[i]=ArrayPos[i]+ArrayVel[i]*RestTime;

  rt2=OldPos[i].dist(ArrayPos[i]);

  // Test If Collision Occured Between Ball And All 5 Planes

  if (TestIntersionPlane(pl1,OldPos[i],uveloc,rt,norm)) {

   // Find Intersection Time

   rt4=rt*RestTime/rt2;

   // If Smaller Than The One Already Stored Replace In Timestep

   if (rt4<=lamda) {

    // If Intersection Time In Current Time Step

    if (rt4<=RestTime+ZERO) if (! ((rt<=ZERO)&&(uveloc.dot(norm)>ZERO)) ) {

     normal=norm;

     point=OldPos[i]+uveloc*rt;

     lamda=rt4;

     BallNr=i;

    }

   }

  }

  if (TestIntersionPlane(pl2, OldPos[i], uveloc, rt, norm)) {

   // …The Same As Above Omitted For Space Reasons

  }

  if (TestIntersionPlane(pl3, OldPos[i], uveloc, rt, norm)) {

   // …The Same As Above Omitted For Space Reasons

  }

  if (TestIntersionPlane(pl4, OldPos[i], uveloc, rt, norm)) {

   // …The Same As Above Omitted For Space Reasons

  }

  if (TestIntersionPlane(pl5, OldPos[i], uveloc, rt, norm)) {

   // …The Same As Above Omitted For Space Reasons

  }

  // Now Test Intersection With The 3 Cylinders

  if (TestIntersionCylinder(cyl1, OldPos[i], uveloc, rt, norm, Nc)) {

   rt4 = rt*RestTime/rt2;

   if (rt4<=lamda) {

    if (rt4<=RestTime+ZERO) if (! ((rt<=ZERO)&&(uveloc.dot(norm)>ZERO)) ) {

     normal=norm;

     point=Nc;

     lamda=rt4;

     BallNr=i;

    }

   }

  }

  if (TestIntersionCylinder(cyl2, OldPos[i], uveloc, rt, norm, Nc)) {

   // …The Same As Above Omitted For Space Reasons

  }

  if (TestIntersionCylinder(cyl3, OldPos[i], uveloc, rt, norm, Nc)) {

   // …The Same As Above Omitted For Space Reasons

  }

 }

 // After All Balls Were Tested With Planes / Cylinders Test For Collision

 // Between Them And Replace If Collision Time Smaller

 if (FindBallCol(Pos2, BallTime, RestTime, BallColNr1, BallColNr2)) {

  if (sounds) PlaySound("Explode.wav", NULL, SND_FILENAME|SND_ASYNC);

  if ((lamda==10000) || (lamda>BallTime)) {

   RestTime=RestTime-BallTime;

   TVector pb1, pb2, xaxis, U1x, U1y, U2x, U2y, V1x, V1y, V2x, V2y;

   double a,b;

   …

   Code Omitted For Space Reasons

   The Code Is Described In The Physically Based Modeling Section Under Sphere To Sphere Collision

   …

   //Update Explosion Array And Insert Explosion

   for(j=0; j<20; j++) {

    if (ExplosionArray[j]._Alpha<=0) {

     ExplosionArray[j]._Alpha=1;

     ExplosionArray[j]._Position=ArrayPos[BallColNr1];

     ExplosionArray[j]._Scale=1;

     break;

    }

   }

   continue;

  }

 }

 // End Of Tests

 // If Collision Occured Move Simulation For The Correct Timestep

 // And Compute Response For The Colliding Ball

 if (lamda != 10000) {

  RestTime-=lamda;

  for (j=0; j<NrOfBalls; j++) ArrayPos[j]=OldPos[j]+ArrayVel[j]*lamda;

  rt2=ArrayVel[BallNr].mag();

  ArrayVel[BallNr].unit();

  ArrayVel[BallNr] = TVector::unit( (normal*(2*normal.dot(-ArrayVel[BallNr]))) + ArrayVel[BallNr] );

  ArrayVel[BallNr] = ArrayVel[BallNr]*rt2;

  // Update Explosion Array And Insert Explosion

  for(j=0; j<20; j++) {

   if (ExplosionArray[j]._Alpha<=0) {

    ExplosionArray[j]._Alpha=1;

    ExplosionArray[j]._Position=point;

    ExplosionArray[j]._Scale=1;

    break;

   }

  }

 } else RestTime=0;

} // End Of While Loop

The Main Global Variables Of Importance Are:

Represent the direction and position of the camera. The camera is moved using the LookAt function. As you will probably notice, if not in hook mode (which I will explain later), the whole scene rotates around, the degree of rotation is handled with camera_rotation. TVector dir TVector pos(0,-50,1000); float camera_rotation=0;
Represent the acceleration applied to the moving balls. Acts as gravity in the application. TVector accel(0,-0.05,0);
Arrays which hold the New and old ball positions and the velocity vector of each ball. The number of balls is hard coded to 10. TVector ArrayVel[10]; TVector ArrayPos[10]; TVector OldPos[10]; int NrOfBalls=3;
The time step we use. double Time=0.6;
If 1 the camera view changes and a (the ball with index 0 in the array) ball is followed. For making the camera following the ball we used its position and velocity vector to position the camera exactly behind the ball and make it look along the velocity vector of the ball. int hook_toball1=0;
Self explanatory structures for holding data about explosions, planes and cylinders. struct Plane struct Cylinder struct Explosion
The explosions are stored in a array, of fixed length. Explosion ExplosionArray[20];

The Main Functions Of Interest Are:

Perform Intersection tests with primitives int TestIntersionPlane(…); int TestIntersionCylinder(…);
Loads Textures from bmp files void LoadGLTextures();
Has the rendering code. Renders the balls, walls, columns and explosions void DrawGLScene();
Performs the main simulation logic void idle();
Sets Up OpenGL state void InitGL();
Find if any balls collide again each other in current time step int FindBallCol(…);