#include "stdafx.h" #define NUM_SPHERES 50 #define StackMax 12 #define YGROUND -0.2f #define EX 0.0f #define EY 1.0f #define EZ 3.0f #define CX 0.0f #define CY YGROUND #define CZ 0.0f #define DELTA_C 0.1f #define DELTA 0.01f #define DELTA_R 0.01f #define DELTATRANS 0.05f #define LIGHT_X 1.5f #define LIGHT_Y 1.5f #define LIGHT_Z 1.0f #define LIGHT_A 1.0f typedef struct {GLfloat vLocation[3]; GLfloat vRotation[3]; } GLTFrame; GLboolean bCull = (GLboolean)true, bDepth= (GLboolean)true, bOutline=(GLboolean)true, bShade= (GLboolean)true; GLsizei wSize=500, hSize =500; GLfloat ambientLight[] = { 0.3f, 0.3f, 0.3f, 1.0f }, diffuseLight[] = { 0.7f, 0.7f, 0.7f, 1.0f }, specular[] = { 1.0f, 1.0f, 1.0f, 1.0f}, specref[] = { 1.0f, 1.0f, 1.0f, 1.0f }, wlightPos[] = { LIGHT_X, LIGHT_Y, LIGHT_Z, LIGHT_A }, Translate_Tor_and_Sph[] = {0.0f, 0.0f, -2.5f}, Rot_Sph_vect[] = {0.0f, 1.0f, 0.0f}, Rot_Torus_vect[] = {0.0f, 1.0f, 0.0f}, Translate_Sph_only[] = {1.0f, 0.5f, 0.0f}, Translate_Tor_only[] = {0.0f, 0.5f, 0.0f}, ex=EX, ey=EY+CY, ez=EZ, cx=CX, cy=CY, cz=CZ, //########### yground = YGROUND, deltaC=DELTA_C, delta= DELTA, deltaR= DELTA_R, deltatrans=DELTATRANS, lightPos[4], LightPosStack[16], //########### shadowMat[16], vGroundPlane[4] = {0.0f, 1.0f, 0.0f, -yground}, colv[4], //work color vector yRot = 0.0f, // Rotation angle for animation fExtent = 20.0f; GLint StackPointer=0; GLTFrame spheres[NUM_SPHERES]; void gltMakeShadowMatrix(GLfloat vPlaneEquation[], GLfloat vLightPos[], GLfloat destMat[]) { GLfloat dot; // Dot product of plane and light position dot = vPlaneEquation[0]*vLightPos[0] + vPlaneEquation[1]*vLightPos[1] + vPlaneEquation[2]*vLightPos[2] + vPlaneEquation[3]*vLightPos[3]; // Now do the projection // First column destMat[0] = dot - vLightPos[0] * vPlaneEquation[0]; destMat[4] = 0.0f - vLightPos[0] * vPlaneEquation[1]; destMat[8] = 0.0f - vLightPos[0] * vPlaneEquation[2]; destMat[12] = 0.0f - vLightPos[0] * vPlaneEquation[3]; // Second column destMat[1] = 0.0f - vLightPos[1] * vPlaneEquation[0]; destMat[5] = dot - vLightPos[1] * vPlaneEquation[1]; destMat[9] = 0.0f - vLightPos[1] * vPlaneEquation[2]; destMat[13] = 0.0f - vLightPos[1] * vPlaneEquation[3]; // Third Column destMat[2] = 0.0f - vLightPos[2] * vPlaneEquation[0]; destMat[6] = 0.0f - vLightPos[2] * vPlaneEquation[1]; destMat[10] = dot - vLightPos[2] * vPlaneEquation[2]; destMat[14] = 0.0f - vLightPos[2] * vPlaneEquation[3]; // Fourth Column destMat[3] = 0.0f - vLightPos[3] * vPlaneEquation[0]; destMat[7] = 0.0f - vLightPos[3] * vPlaneEquation[1]; destMat[11] = 0.0f - vLightPos[3] * vPlaneEquation[2]; destMat[15] = dot - vLightPos[3] * vPlaneEquation[3]; } void gltInitFrame(GLTFrame *f) {f->vLocation[0]=0.0f; f->vLocation[1]=0.0f; f->vLocation[2]=0.0f; f->vRotation[0]=0.0f; f->vRotation[1]=0.0f; f->vRotation[2]=0.0f; return; } void gltApplyActorTransform(GLTFrame *sphere) { glLoadIdentity (); glTranslatef(sphere->vLocation[0], sphere->vLocation[1], sphere->vLocation[2]); } void SetLightPos(GLfloat v[]) { lightPos[0]=v[0]; lightPos[1]=v[1]; lightPos[2]=v[2]; lightPos[3]=v[3]; glLightfv(GL_LIGHT0,GL_POSITION,lightPos); gltMakeShadowMatrix(vGroundPlane, lightPos, shadowMat); } void PushLightStack() {if (StackPointer==StackMax){exit(110);} for (int i=0; i<4; i++) LightPosStack[StackPointer+i]=lightPos[i]; StackPointer+=4; } void Buff_Light() {wlightPos[0]=lightPos[0]; wlightPos[1]=lightPos[1]; wlightPos[2]=lightPos[2]; wlightPos[3]=lightPos[3]; } //// Draw a gridded ground // void DrawGround(void) { GLfloat fStep = 1.0f, wf=20.0f; GLint iLine, jLine, number_steps= 2.0*fExtent/fStep, i,j; GLfloat fi,fj, fk, fn=2.0f*(GLfloat)number_steps, col; colv[3]=0.75f; glBegin(GL_QUADS); for(iLine = -fExtent, i=0, fi=1.0f; iLine <= fExtent; iLine += fStep, i++, fi++) for(jLine = -fExtent, j=0, fj=1.0f; jLine <= fExtent; jLine += fStep, j++, fj++) { fk=(GLfloat) ((i+j)%2); col=(fk*(fi+fj)+wf)/(fn+wf); colv[0]=col; colv[1]=col; colv[2]=col; glNormal3f(0.0f, 1.0f, 0.0f); glColor4fv(colv); glVertex3f(iLine, yground, jLine); col=(fk*(fi+fj+1.0f)+wf)/(fn+wf); colv[0]=col; colv[1]=col; colv[2]=col; glColor4fv(colv); glVertex3f(iLine, yground, jLine+fStep); col=(fk*(fi+fj+2.0f)+wf)/(fn+wf); colv[0]=col; colv[1]=col; colv[2]=col; glColor4fv(colv); glVertex3f(iLine+fStep, yground, jLine+fStep); col=(fk*(fi+fj+1.0f)+wf)/(fn+wf); colv[0]=col; colv[1]=col; colv[2]=col; glColor4fv(colv); glVertex3f(iLine+fStep, yground, jLine); } glEnd(); } void SetupRC() { int iSphere; // Randomly place the sphere inhabitants for(iSphere = 0; iSphere < NUM_SPHERES; iSphere++) { gltInitFrame(&spheres[iSphere]); // Initialize the frame // Pick a random location between -20 and 20 at .1 increments spheres[iSphere].vLocation[0] = (float)((rand() % 400) - 200) * 0.1f; spheres[iSphere].vLocation[1] = 0.1f; spheres[iSphere].vLocation[2] = (float)((rand() % 400) - 200) * 0.1f; } // Bluish background glClearColor(0.0f, 0.0f, .50f, 1.0f ); // Set color shading model to flat glShadeModel(GL_FLAT); // Clockwise-wound polygons are front facing; this is reversed // because we are using triangle fans glFrontFace(GL_CCW); // Enable lighting glEnable(GL_LIGHTING); glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST);/* glPolygonMode(GL_FRONT, GL_FILL); glPolygonMode(GL_BACK, GL_LINE)*/; glPolygonMode(GL_BACK,GL_FILL); // the light source GL_LIGHT0 is enabled: // Set up and enable light 0 glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight); glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight); glLightfv(GL_LIGHT0,GL_SPECULAR,specular); glEnable(GL_LIGHT0); SetLightPos(wlightPos); /* + glLightfv(GL_LIGHT0,GL_POSITION,lightPos); + Calculate projection matrix to draw shadow on the ground: gltMakeShadowMatrix(vGroundPlane, lightPos, shadowMat);*/ // Enable color tracking glEnable(GL_COLOR_MATERIAL); // Front material ambient and diffuse colors track glColor glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE); // All materials hereafter have full specular reflectivity // with a high shine glMaterialfv(GL_FRONT, GL_SPECULAR,specref); glMateriali(GL_FRONT,GL_SHININESS,128); // Light blue background glClearColor(0.0f, 0.0f, 1.0f, 1.0f ); } // Called to draw scene void Draw_Objects_Shadow(void) { glPushMatrix(); // Multiply by shadow projection matrix glLightfv(GL_LIGHT0,GL_POSITION,lightPos); gltMakeShadowMatrix(vGroundPlane, lightPos, shadowMat); glMultMatrixf((GLfloat *)shadowMat); glColor3f(0.25f, 0.25f, 0.25f); // Draw the randomly located spheres for(int i = 0; i < NUM_SPHERES; i++) { glPushMatrix(); gltApplyActorTransform(&spheres[i]); glutSolidSphere(0.1f, 13, 26); glPopMatrix(); } glPushMatrix(); glTranslatef(Translate_Tor_and_Sph[0], Translate_Tor_and_Sph[1], Translate_Tor_and_Sph[2]); glPushMatrix(); glRotatef(-yRot * 2.0f, Rot_Sph_vect[0], Rot_Sph_vect[1],Rot_Sph_vect[2]); glTranslatef(Translate_Sph_only[0], Translate_Sph_only[1], Translate_Sph_only[2]); glutSolidSphere(0.1f, 13, 26); glPopMatrix(); glPushMatrix(); glRotatef(yRot, Rot_Torus_vect[0], Rot_Torus_vect[1], Rot_Torus_vect[2]); glTranslatef(Translate_Tor_only[0], Translate_Tor_only[1], Translate_Tor_only[2]); glutSolidTorus(0.15, 0.35, 40, 20); // gltDrawTorus(0.35, 0.15, 40, 20); glPopMatrix(); glPopMatrix(); glPopMatrix(); } void Draw_Objects(void) { // Draw the randomly located spheres glPushMatrix(); for(int i = 0; i < NUM_SPHERES; i++) { glPushMatrix(); gltApplyActorTransform(&spheres[i]); glutSolidSphere(0.1f, 13, 26); glPopMatrix(); } glPushMatrix(); glTranslatef(Translate_Tor_and_Sph[0], Translate_Tor_and_Sph[1], Translate_Tor_and_Sph[2]); glPushMatrix(); colv[0]=0.0f; colv[1]=0.5f; colv[2]=0.5f; glColor4fv(colv); glRotatef(-yRot * 2.0f, Rot_Sph_vect[0], Rot_Sph_vect[1], Rot_Sph_vect[2]); glTranslatef(Translate_Sph_only[0], Translate_Sph_only[1], Translate_Sph_only[2]); glutSolidSphere(0.1f, 13, 26); glPopMatrix(); colv[0]=1.0f; colv[1]=0.0f; colv[2]=0.0f; glColor4fv(colv); glPushMatrix(); glRotatef(yRot, Rot_Torus_vect[0], Rot_Torus_vect[1], Rot_Torus_vect[2]); glTranslatef(Translate_Tor_only[0], Translate_Tor_only[1], Translate_Tor_only[2]); glutSolidTorus(0.15, 0.35, 40, 20); //void glutSolidTorus(GLdouble innerRadius, //GLdouble outerRadius, GLint nsides, GLint rings); glPopMatrix(); glPopMatrix(); glPopMatrix(); } void Draw_Light(void){ glPushMatrix(); colv[0]=1.0f; colv[1]=1.0f; colv[2]=0.0f; glColor4fv(colv); glTranslatef(lightPos[0],lightPos[1], lightPos[2]); glutSolidSphere(0.1f,10,10); glPopMatrix(); } void DrawWorld_with_Shadows() // objects + shadows; no ground, nor the light source { // First disable lighting and save the projection state glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); Draw_Objects_Shadow(); glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); Draw_Objects(); Draw_Light(); } void RenderScene(void) { // Reset coordinate system glLoadIdentity(); gluLookAt (ex, ey, ez, cx, cy, cz, 0.0, 1.0, 0.0); // Clear the window with current clearing color glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); //reflected world glFrontFace(GL_CW); // swap orientation glPushMatrix(); glScalef(1.0f, -1.0f, 1.0f); // geometry is mirrored by ground glTranslatef(0.0f, -2.0f*yground, 0.0f); Draw_Objects(); Draw_Light(); glPopMatrix(); glFrontFace(GL_CCW); // Draw the ground transparently over the reflection glDisable(GL_LIGHTING); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //floor DrawGround(); glDisable(GL_BLEND); glEnable(GL_LIGHTING); glPopMatrix(); //normal world, the source of light and shadows DrawWorld_with_Shadows(); glutSwapBuffers(); } // Called by GLUT library when the window has changed size void ChangeSize(GLsizei w, GLsizei h) { // Set Viewport to window dimensions glViewport(0, 0, (GLsizei)w, (GLsizei)h); wSize=(GLsizei)w; hSize=(GLsizei)h; glMatrixMode(GL_PROJECTION); glLoadIdentity(); //glOrtho (-100.0, 100.0, -100, 100, -270.0, 270.0); //glFrustum (-1.0, 1.0, -1.0, 1.0, 1.5, 20.0); gluPerspective(60.0, 1.0, 1.5, 700.0); glMatrixMode (GL_MODELVIEW); } void SpecialKeys(int key, int x, int y) {GLfloat dx, dy, dz, dx0, dy0, dz0; if(key == GLUT_KEY_UP) {//increase distance from camera to origin dx=cx-ex; dy=cy-ey; dz=cz-ez; ex-=deltaR*dx; ey-=deltaR*dy; ez-=deltaR*dz; yRot += 0.5f; glutPostRedisplay(); return; } if(key == GLUT_KEY_DOWN) {//reduce distance from camera to origin (close up) dx=cx-ex; dy=cy-ey; dz=cz-ez; ex+=deltaR*dx; ey+=deltaR*dy; ez+=deltaR*dz; yRot += 0.5f; glutPostRedisplay(); return; } if(key == GLUT_KEY_LEFT) //Rotate (+) camera around origin in Oxz plane { dx0=cz-ez; dz0= ex - cx; dx=cx-ex; dz=cz-ez; GLfloat s=sqrtf(dx*dx+dz*dz); dx+=delta*dx0; dz+=delta*dz0; GLfloat s1=sqrtf(dx*dx+dz*dz)/s; dx/=s1; dz/=s1; ex=cx-dx; ez=cz-dz; yRot += 0.5f; glutPostRedisplay();return; } if(key == GLUT_KEY_RIGHT) //Rotate (-) camera around origin in Oxz plane {dx0=cz-ez; dz0= ex - cx; dx=cx-ex; dz=cz-ez; GLfloat s=sqrtf(dx*dx+dz*dz); dx-=delta*dx0; dz-=delta*dz0; GLfloat s1=sqrtf(dx*dx+dz*dz)/s; dx/=s1; dz/=s1; ex=cx-dx; ez=cz-dz; yRot += 0.5f; glutPostRedisplay();return;} if(key == GLUT_KEY_F5)//Rotate camera around scene center in Oyz plane { dy0=cz-ez; dz0= ey - cy; dy=cy-ey; dz=cz-ez; GLfloat s=sqrtf(dy*dy+dz*dz); dy+=delta*dy0; dz+=delta*dz0; GLfloat s1=sqrtf(dy*dy+dz*dz)/s; dy/=s1; dz/=s1; ey=cy-dy; ez=cz-dz; yRot += 0.5f; glutPostRedisplay();return;} if(key == GLUT_KEY_F6)//Rotate camera around scene center in Oyz plane {dy0=cz-ez; dz0= ey - cy; dy=cy-ey; dz=cz-ez; GLfloat s=sqrtf(dy*dy+dz*dz); dy-=delta*dy0; dz-=delta*dz0; GLfloat s1=sqrtf(dy*dy+dz*dz)/s; dy/=s1; dz/=s1; ey=cy-dy; ez=cz-dz; yRot += 0.5f; glutPostRedisplay();return;} if(key == GLUT_KEY_F7)//Move light toward the center of ground { dx=cx-lightPos[0]; dy=cy-lightPos[1]; dz=cz-lightPos[2]; dx*=(1.0-deltatrans); dy*=(1.0-deltatrans); dz*=(1.0-deltatrans); lightPos[0]=cx-dx; lightPos[1]=cy-dy; lightPos[2]=cz-dz;//##### // SetLightPos(wlightPos); // Calculate new projection matrix to draw shadow on the ground yRot += 0.5f; glutPostRedisplay();return; } if(key == GLUT_KEY_F8)//Move light outward the center of ground { dx=cx-lightPos[0]; dy=cy-lightPos[1]; dz=cz-lightPos[2]; dx/=(1.0-deltatrans); dy/=(1.0-deltatrans); dz/=(1.0-deltatrans); lightPos[0]=cx-dx; lightPos[1]=cy-dy; lightPos[2]=cz-dz;//##### // SetLightPos(wlightPos); // Calculate new projection matrix to draw shadow on the ground yRot += 0.5f; glutPostRedisplay();return; } if(key == GLUT_KEY_F9)//Rotate (+) light around ... in the vertical plane { dy0=cz-lightPos[2]; dz0= lightPos[1] - cy; dy=cy-lightPos[1]; dz=cz-lightPos[2]; GLfloat s=sqrtf(dy*dy+dz*dz); dy+=delta*dy0; dz+=delta*dz0; GLfloat s1=sqrtf(dy*dy+dz*dz)/s; dy/=s1; dz/=s1; lightPos[1]=cy-dy; lightPos[2]=cz-dz;//##### yRot += 0.5f; glutPostRedisplay();return; } if(key == GLUT_KEY_F10)//Rotate (-) light around ... in the vertical plane { dy0=cz-lightPos[2]; dz0= lightPos[1] - cy; dy=cy-lightPos[1]; dz=cz-lightPos[2]; GLfloat s=sqrtf(dy*dy+dz*dz); dy-=delta*dy0; dz-=delta*dz0; GLfloat s1=sqrtf(dy*dy+dz*dz)/s; dy/=s1; dz/=s1; lightPos[1]=cy-dy; lightPos[2]=cz-dz;//##### yRot += 0.5f; glutPostRedisplay();return; } if(key == GLUT_KEY_F11)//Rote light around ... in the horizontal plane { dy=-lightPos[2]; dz= lightPos[0]; GLfloat s=sqrtf(lightPos[0]*lightPos[0]+lightPos[1]*lightPos[1] +lightPos[2]*lightPos[2]); //##################### lightPos[0]+=delta*dy; lightPos[2]+=delta*dz; GLfloat s1=sqrtf(lightPos[0]*lightPos[0]+lightPos[1]*lightPos[1] +lightPos[2]*lightPos[2])/s; lightPos[0]/=s1; lightPos[1]/=s1; lightPos[2]/=s1; //##################### yRot += 0.5f; glutPostRedisplay();return; } if(key == GLUT_KEY_F12)//Move light in horiz. plane { dy=lightPos[0]; dz= lightPos[2]; //##################### lightPos[0]+=delta*dy; lightPos[2]+=delta*dz; //##################### yRot += 0.5f; glutPostRedisplay();return; } if(key == GLUT_KEY_F1){ bCull=!bCull; // Turn on/off culling on if flag is set if(bCull) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); yRot += 0.5f; glutPostRedisplay();return; } if(key == GLUT_KEY_F2){bDepth=!bDepth; if(bDepth) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); yRot += 0.5f; glutPostRedisplay();return; } if(key == GLUT_KEY_F3){bOutline=!bOutline; // Draw the back side as a wireframe only, if flag is set if(bOutline)glPolygonMode(GL_BACK,GL_LINE); else glPolygonMode(GL_BACK,GL_FILL); yRot += 0.5f; glutPostRedisplay(); return; } if(key == GLUT_KEY_F4) {bShade=!bShade; if(bShade){glShadeModel(GL_FLAT);} else {glShadeModel(GL_SMOOTH);} yRot += 0.5f; glutPostRedisplay(); return; } } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB); glutInitWindowSize (wSize, hSize); glutInitWindowPosition (100, 100); glutCreateWindow (argv[0]); glutDisplayFunc(RenderScene); glutReshapeFunc(ChangeSize); glutSpecialFunc (SpecialKeys); SetupRC(); glutMainLoop(); return 0; }