/* Demonstrates how to compute the intersection of a line with a plane. This is used to compute the intersection of a laser beam with the roof of the barn. Written by Scott D. Anderson and Caroline Geiersbach scott.anderson@acm.org Summer 2003 */ #include #include #include // for random #include // for FLT_MAX #include // ================================================================ twTriple UFOpos = {75,80,-25}; twTriple UFOdir = {-.2,0,-.2}; twTriple LaserDir = {0,-1,0}; int Frame=0; // which frame of animation int SubFrame=0; // subframe for shooting photo torpedos // yes, this recomputes IP every time. It's not a efficient as it could be void blast(twTriple LaserPoint, twTriple LaserDir) { twFragment fragments[] = { // ground {{0,0,0},{100,0,0},{0,0,-100}}, // roof, right half {{15,40,-50},{15,40,-100},{30,0.7*40,-50}} }; twTriple IP; // intersection point GLfloat r; // intersection parameter twVectorNormalize(LaserDir); /* Compute the parameter of the nearest intersection, if any. The intersection point, IP, is computed, as is its parameter, r. "r" is essentially the distance of IP from LaserPoint, in units of LaserDir, which is of unit length. */ bool blast = twNearestFragment(fragments,2,LaserPoint,LaserDir,IP,r); /* The maximum distance the torpedo could ever go is approximately sqrt(2)*100, since the UFO is 100 units high and the maximum angle is 45 degrees. This divides that maximum distance into 10 steps (because of the multiplication by 0.1) and determines which step using the SubFrame parameter. The result is the distance of the torpedo from its launch point. */ GLfloat torpedoParam = 0.1*sqrt(2)*100*SubFrame; twColorName(TW_MAGENTA); if( blast && torpedoParam > r ) { // the torpedo is farther than the intersection point, so draw a // blast, of increasing radius, with a minimum radius of 5. if( SubFrame < 5 ) SubFrame = 5; glPushMatrix(); glTranslatef(IP[0],IP[1],IP[2]); glutSolidSphere(SubFrame,20,20); glPopMatrix(); } else { // draw photonTorpedo, because it hasn't reached the IP yet twTriple photonTorpedo; twPointOnLine(photonTorpedo,UFOpos,LaserDir,torpedoParam); glPointSize(5); glBegin(GL_POINTS); glVertex3fv(photonTorpedo); glEnd(); } } void display(void) { twDisplayInit(); twCamera(); // step 1 camera twColorName(TW_GREEN); twGround(); glPushMatrix(); glTranslatef(0,0,-50); glScalef(30,40,50); twTriple red = {1, 0, 0}; twTriple dark = { 0.2, 0.2, 0.2 }; twSolidBarn(red,red,dark); // red barn with dark roof glPopMatrix(); glPushMatrix(); glTranslatef(UFOpos[0],UFOpos[1],UFOpos[2]); glPushMatrix(); glScalef(10,5,10); twColorName(TW_PURPLE); glutSolidSphere(1,20,20); // UFO glPopMatrix(); glLineWidth(3); glBegin(GL_LINES); glVertex3f(0,0,0); twVectorNormalize(LaserDir); // laser weapon is always 20 units long twVectorScale(LaserDir,LaserDir,20); glVertex3fv(LaserDir); glEnd(); glPopMatrix(); blast(UFOpos,LaserDir); glFlush(); glutSwapBuffers(); } // random float between 0 and 1 float urandom01() { return ((float) random())/((float) RAND_MAX); } // roughly gaussian with mean zero and variance=samples/12 float random(int samples) { float x = 0.0; for(int i=0; i