VECTOR4D VECTOR4D::GetRotatedAxis(double angle, const VECTOR3D & axis) const { VECTOR3D v3d(x, y, z); v3d.RotateAxis(angle, axis); return VECTOR4D(v3d.x, v3d.y, v3d.z, w); }
VECTOR4D VECTOR4D::GetRotatedZ(double angle) const { VECTOR3D v3d(x, y, z); v3d.RotateZ(angle); return VECTOR4D(v3d.x, v3d.y, v3d.z, w); }
//Perform per frame updates void UpdateFrame(unsigned char key, int x, int y) { angle=(float)timer.GetTime()/25; objectLightDirection=worldLightDirection.GetRotatedY(-angle); objectViewDirection=worldViewDirection.GetRotatedY(-angle); //update vertex program registers //Light direction in c[4] glProgramParameter4fvNV(GL_VERTEX_PROGRAM_NV, 4, VECTOR4D(objectLightDirection.GetNormalized())); //view direction in c[5] glProgramParameter4fvNV(GL_VERTEX_PROGRAM_NV, 5, VECTOR4D(objectViewDirection.GetNormalized())); // //pause & unpause // if(window.isKeyPressed('P')) // timer.Pause(); // // if(window.isKeyPressed('U')) // timer.Unpause(); // // //change technique // if(window.isKeyPressed('1') && paths1And2Supported) // currentTechnique=SINGLE_PASS; // // if(window.isKeyPressed('2') && paths1And2Supported) // currentTechnique=TEXTURE_LOOKUP; // // if(window.isKeyPressed('3')) // currentTechnique=FALLBACK; // // //toggle bumpy // if(window.isKeyPressed('B')) // showBumps=true; // // if(window.isKeyPressed('F')) // showBumps=false; }
//Called to draw scene void Display(void) { //angle of spheres in scene. Calculate from time float angle=timer.GetTime()/10; //First pass - from light's point of view glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadMatrixf(lightProjectionMatrix); glMatrixMode(GL_MODELVIEW); glLoadMatrixf(lightViewMatrix); //Use viewport the same size as the shadow map glViewport(0, 0, shadowMapSize, shadowMapSize); //Draw back faces into the shadow map glCullFace(GL_FRONT); //Disable color writes, and use flat shading for speed glShadeModel(GL_FLAT); glColorMask(0, 0, 0, 0); //Draw the scene DrawScene(angle); //Read the depth buffer into the shadow map texture glBindTexture(GL_TEXTURE_2D, shadowMapTexture); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, shadowMapSize, shadowMapSize); //restore states glCullFace(GL_BACK); glShadeModel(GL_SMOOTH); glColorMask(1, 1, 1, 1); //2nd pass - Draw from camera's point of view glClear(GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadMatrixf(cameraProjectionMatrix); glMatrixMode(GL_MODELVIEW); glLoadMatrixf(cameraViewMatrix); glViewport(0, 0, windowWidth, windowHeight); //Use dim light to represent shadowed areas glLightfv(GL_LIGHT1, GL_POSITION, VECTOR4D(lightPosition)); glLightfv(GL_LIGHT1, GL_AMBIENT, white*0.2f); glLightfv(GL_LIGHT1, GL_DIFFUSE, white*0.2f); glLightfv(GL_LIGHT1, GL_SPECULAR, black); glEnable(GL_LIGHT1); glEnable(GL_LIGHTING); DrawScene(angle); //3rd pass //Draw with bright light glLightfv(GL_LIGHT1, GL_DIFFUSE, white); glLightfv(GL_LIGHT1, GL_SPECULAR, white); //Calculate texture matrix for projection //This matrix takes us from eye space to the light's clip space //It is postmultiplied by the inverse of the current view matrix when specifying texgen static MATRIX4X4 biasMatrix(0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f); //bias from [-1, 1] to [0, 1] MATRIX4X4 textureMatrix=biasMatrix*lightProjectionMatrix*lightViewMatrix; //MATRIX4X4 textureMatrix=lightProjectionMatrix*lightViewMatrix; //Set up texture coordinate generation. glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGenfv(GL_S, GL_EYE_PLANE, textureMatrix.GetRow(0)); glEnable(GL_TEXTURE_GEN_S); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGenfv(GL_T, GL_EYE_PLANE, textureMatrix.GetRow(1)); glEnable(GL_TEXTURE_GEN_T); glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGenfv(GL_R, GL_EYE_PLANE, textureMatrix.GetRow(2)); glEnable(GL_TEXTURE_GEN_R); glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGenfv(GL_Q, GL_EYE_PLANE, textureMatrix.GetRow(3)); glEnable(GL_TEXTURE_GEN_Q); //Bind & enable shadow map texture glBindTexture(GL_TEXTURE_2D, shadowMapTexture); glEnable(GL_TEXTURE_2D); //Enable shadow comparison glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE); //Shadow comparison should be true (ie not in shadow) if r<=texture glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); //Shadow comparison should generate an INTENSITY result glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY); //Set alpha test to discard false comparisons glAlphaFunc(GL_GEQUAL, 0.99f); glEnable(GL_ALPHA_TEST); DrawScene(angle); //Disable textures and texgen glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); glDisable(GL_TEXTURE_GEN_R); glDisable(GL_TEXTURE_GEN_Q); //Restore other states glDisable(GL_LIGHTING); glDisable(GL_ALPHA_TEST); //Update frames per second counter fpsCounter.Update(); //Print fps static char fpsString[32]; sprintf(fpsString, "%.2f", fpsCounter.GetFps()); //Set matrices for ortho glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluOrtho2D(-1.0f, 1.0f, -1.0f, 1.0f); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); //Print text glRasterPos2f(-1.0f, 0.9f); for(unsigned int i=0; i<strlen(fpsString); ++i) glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, fpsString[i]); //reset matrices glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glFinish(); glutSwapBuffers(); glutPostRedisplay(); }
//Render a frame void RenderFrame(double currentTime, double timePassed) { //Clear buffers glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); //reset modelview matrix glColor4f(1.0f, 1.0f, 1.0f, 1.0f); gluLookAt( 0.0f, 1.8f, 1.8f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0); //Enable texture glBindTexture(GL_TEXTURE_2D, floorTexture); glEnable(GL_TEXTURE_2D); //Set up vertex arrays glVertexPointer(3, GL_FLOAT, sizeof(SIMPLE_VERTEX), &vertices[0].position); glEnableClientState(GL_VERTEX_ARRAY); glNormalPointer(GL_FLOAT, sizeof(SIMPLE_VERTEX), &vertices[0].normal); glEnableClientState(GL_NORMAL_ARRAY); glTexCoordPointer(2, GL_FLOAT, sizeof(SIMPLE_VERTEX), &vertices[0].texCoords); glEnableClientState(GL_TEXTURE_COORD_ARRAY); //Use Fixed Function Pipeline if(useFixedFunction) { //Set parameters for GL lighting glLightModelfv(GL_LIGHT_MODEL_AMBIENT, white*0.1f); //global ambient glMaterialfv(GL_FRONT, GL_AMBIENT, white); glMaterialfv(GL_FRONT, GL_DIFFUSE, white); glEnable(GL_LIGHTING); //8 passes, dealing with 8 lights at a time, except final pass where we do 4 for(int i=0; i<8; ++i) { int numLightsThisPass=8; if(i==7) numLightsThisPass=4; //Set up lights for(int j=0; j<numLightsThisPass; ++j) { glLightfv(GL_LIGHT0+j, GL_POSITION, VECTOR4D(lights[i*8+j].position)); glLightfv(GL_LIGHT0+j, GL_DIFFUSE, lights[i*8+j].color); glEnable(GL_LIGHT0+j); } //If this is the final pass, disable lights 4-7 if(i==7) for(int j=4; j<7; ++j) glDisable(GL_LIGHT0+j); //Enable additive blend for all passes except the first if(i!=0) { glBlendFunc(GL_ONE, GL_ONE); glEnable(GL_BLEND); //if this is not the first pass, no ambient glLightModelfv(GL_LIGHT_MODEL_AMBIENT, black); } //Draw grid as triangle strips for(int j=0; j<gridDensity-1; ++j) glDrawElements( GL_TRIANGLE_STRIP, gridDensity*2, GL_UNSIGNED_INT, &indices[j*gridDensity*2]); } //Disable lights for(int j=0; j<7; ++j) glDisable(GL_LIGHT0+j); glDisable(GL_LIGHTING); glDisable(GL_BLEND); } //Use vp1 if(useVP1) { //Bind program glBindProgramNV(GL_VERTEX_PROGRAM_NV, vp1); glEnable(GL_VERTEX_PROGRAM_NV); //3 passes, dealing with 20 lights at a time for(int i=0; i<3; ++i) { //Send ambient brightness as c[4] //Only send this for the first pass if(i==0) glProgramParameter4fvNV(GL_VERTEX_PROGRAM_NV, 4, white*0.1f); else glProgramParameter4fvNV(GL_VERTEX_PROGRAM_NV, 4, black); //Update program parameters 5&6 for light0, 7&8 for light1, etc for(int j=0; j<20; ++j) { glProgramParameter4fvNV(GL_VERTEX_PROGRAM_NV, 2*j+5, VECTOR4D(lights[i*20+j].position)); glProgramParameter4fvNV(GL_VERTEX_PROGRAM_NV, 2*j+6, lights[i*20+j].color); } //Enable additive blend for passes except the first if(i>0) { glBlendFunc(GL_ONE, GL_ONE); glEnable(GL_BLEND); } //Draw grid as triangle strips for(int j=0; j<gridDensity-1; ++j) glDrawElements( GL_TRIANGLE_STRIP, gridDensity*2, GL_UNSIGNED_INT, &indices[j*gridDensity*2]); } glDisable(GL_VERTEX_PROGRAM_NV); glDisable(GL_BLEND); } //Use vp2 if(useVP2) { //Bind program glBindProgramNV(GL_VERTEX_PROGRAM_NV, vp2); glEnable(GL_VERTEX_PROGRAM_NV); //Send ambient brightness as c[4] glProgramParameter4fvNV(GL_VERTEX_PROGRAM_NV, 4, white*0.1f); //Update program parameters 5&6 for light0, 7&8 for light1, etc for(int j=0; j<60; ++j) { glProgramParameter4fvNV(GL_VERTEX_PROGRAM_NV, 2*j+5, VECTOR4D(lights[j].position)); glProgramParameter4fvNV(GL_VERTEX_PROGRAM_NV, 2*j+6, lights[j].color); } //Send loop parameters to c[125] glProgramParameter4fNV(GL_VERTEX_PROGRAM_NV, 125, 60.0, //number of lights 5.0, //base offset of light data -1.0, 2.0);//num parameters between lights //Draw grid as triangle strips for(int j=0; j<gridDensity-1; ++j) glDrawElements( GL_TRIANGLE_STRIP, gridDensity*2, GL_UNSIGNED_INT, &indices[j*gridDensity*2]); glDisable(GL_VERTEX_PROGRAM_NV); } //reset states glDisable(GL_TEXTURE_2D); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); fpsCounter.Update(); //Print text font.StartTextMode(); glColor4f(0.0f, 1.0f, 0.0f, 1.0f); font.Print(0, 28, "FPS: %.2f", fpsCounter.GetFps()); glColor4f(1.0f, 0.0f, 0.0f, 0.0f); if(useVP1) font.Print(0, 48, "Using NV_vertex_program"); if(useVP2) font.Print(0, 48, "Using NV_vertex_program2"); if(useFixedFunction) font.Print(0, 48, "Using Fixed Function Pipeline"); font.EndTextMode(); WINDOW::Instance()->SwapBuffers(); //Save a screenshot if(WINDOW::Instance()->IsKeyPressed(VK_F1)) { WINDOW::Instance()->SaveScreenshot(); WINDOW::Instance()->SetKeyReleased(VK_F1); } //Check for an openGL error WINDOW::Instance()->CheckGLError(); //quit if necessary if(WINDOW::Instance()->IsKeyPressed(VK_ESCAPE)) PostQuitMessage(0); }
//Called to draw scene void Display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); //use gluLookAt to look at torus gluLookAt( 0.0f,10.0f,10.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f); //rotate torus static float angle=0.0f; angle+=0.1f; glRotatef(angle, 0.0f, 1.0f, 0.0f); //Get the inverse model matrix MATRIX4X4 inverseModelMatrix; glPushMatrix(); glLoadIdentity(); glRotatef(-angle, 0.0f, 1.0f, 0.0f); glGetFloatv(GL_MODELVIEW_MATRIX, inverseModelMatrix); glPopMatrix(); //Get the object space light vector VECTOR3D objectLightPosition=inverseModelMatrix*worldLightPosition; //Loop through vertices for(int i=0; i<torus.numVertices; ++i) { VECTOR3D lightVector=objectLightPosition-torus.vertices[i].position; //Calculate tangent space light vector torus.vertices[i].tangentSpaceLight.x= torus.vertices[i].sTangent.DotProduct(lightVector); torus.vertices[i].tangentSpaceLight.y= torus.vertices[i].tTangent.DotProduct(lightVector); torus.vertices[i].tangentSpaceLight.z= torus.vertices[i].normal.DotProduct(lightVector); } //Draw bump pass if(drawBumps) { //Bind normal map to texture unit 0 glBindTexture(GL_TEXTURE_2D, normalMap); glEnable(GL_TEXTURE_2D); //Bind normalisation cube map to texture unit 1 glActiveTexture(GL_TEXTURE1_ARB); glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, normalisationCubeMap); glEnable(GL_TEXTURE_CUBE_MAP_ARB); glActiveTextureARB(GL_TEXTURE0_ARB); //Set vertex arrays for torus glVertexPointer(3, GL_FLOAT, sizeof(TORUS_VERTEX), &torus.vertices[0].position); glEnableClientState(GL_VERTEX_ARRAY); //Send texture coords for normal map to unit 0 glTexCoordPointer(2, GL_FLOAT, sizeof(TORUS_VERTEX), &torus.vertices[0].s); glEnableClientState(GL_TEXTURE_COORD_ARRAY); //Send tangent space light vectors for normalisation to unit 1 glClientActiveTexture(GL_TEXTURE1_ARB); glTexCoordPointer(3, GL_FLOAT, sizeof(TORUS_VERTEX), &torus.vertices[0].tangentSpaceLight); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glClientActiveTexture(GL_TEXTURE0_ARB); //Set up texture environment to do (tex0 dot tex1)*color glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE); glActiveTextureARB(GL_TEXTURE1_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGB_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); glActiveTextureARB(GL_TEXTURE0_ARB); //Draw torus glDrawElements(GL_TRIANGLES, torus.numIndices, GL_UNSIGNED_INT, torus.indices); //Disable textures glDisable(GL_TEXTURE_2D); glActiveTextureARB(GL_TEXTURE1_ARB); glDisable(GL_TEXTURE_CUBE_MAP_ARB); glActiveTextureARB(GL_TEXTURE0_ARB); //disable vertex arrays glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glClientActiveTexture(GL_TEXTURE1_ARB); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glClientActiveTexture(GL_TEXTURE0_ARB); //Return to standard modulate texenv glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } //If we are drawing both passes, enable blending to multiply them together if(drawBumps && drawColor) { //Enable multiplicative blending glBlendFunc(GL_DST_COLOR, GL_ZERO); glEnable(GL_BLEND); } //Perform a second pass to color the torus if(drawColor) { if(!drawBumps) { glLightfv(GL_LIGHT1, GL_POSITION, VECTOR4D(objectLightPosition)); glLightfv(GL_LIGHT1, GL_DIFFUSE, white); glLightfv(GL_LIGHT1, GL_AMBIENT, black); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, black); glEnable(GL_LIGHT1); glEnable(GL_LIGHTING); glMaterialfv(GL_FRONT, GL_DIFFUSE, white); } //Bind decal texture glBindTexture(GL_TEXTURE_2D, decalTexture); glEnable(GL_TEXTURE_2D); //Set vertex arrays for torus glVertexPointer(3, GL_FLOAT, sizeof(TORUS_VERTEX), &torus.vertices[0].position); glEnableClientState(GL_VERTEX_ARRAY); glNormalPointer(GL_FLOAT, sizeof(TORUS_VERTEX), &torus.vertices[0].normal); glEnableClientState(GL_NORMAL_ARRAY); glTexCoordPointer(2, GL_FLOAT, sizeof(TORUS_VERTEX), &torus.vertices[0].s); glEnableClientState(GL_TEXTURE_COORD_ARRAY); //Draw torus glDrawElements(GL_TRIANGLES, torus.numIndices, GL_UNSIGNED_INT, torus.indices); if(!drawBumps) glDisable(GL_LIGHTING); //Disable texture glDisable(GL_TEXTURE_2D); //disable vertex arrays glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } //Disable blending if it is enabled if(drawBumps && drawColor) glDisable(GL_BLEND); glFinish(); glutSwapBuffers(); glutPostRedisplay(); }