#include #include #include #include #include GLUquadric *quadSphere, *quadCyl; int windowWidth; // Rotate the scene about the Y axis GLfloat yrot; // Location of the target and camera objects, respectively float target[3], camera[3]; #define DELTA 0.25f static void key (unsigned char k, int x, int y) { switch (k) { case 'q': target[0] -= DELTA; break; case 'Q': target[0] += DELTA; break; case 'w': target[1] -= DELTA; break; case 'W': target[1] += DELTA; break; case 'e': target[2] -= DELTA; break; case 'E': target[2] += DELTA; break; case 'a': camera[0] -= DELTA; break; case 'A': camera[0] += DELTA; break; case 's': camera[1] -= DELTA; break; case 'S': camera[1] += DELTA; break; case 'd': camera[2] -= DELTA; break; case 'D': camera[2] += DELTA; break; break; default: exit(0); } glutPostRedisplay (); } // Calculate the cross product and return it static void cross (float dst[3], float srcA[3], float srcB[3]) { dst[0] = srcA[1]*srcB[2] - srcA[2]*srcB[1]; dst[1] = srcA[2]*srcB[0] - srcA[0]*srcB[2]; dst[2] = srcA[0]*srcB[1] - srcA[1]*srcB[0]; } // Normalize the input vector static void normalize (float vec[3]) { const float squaredLen = vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]; const float invLen = 1.f / (float) sqrt (squaredLen); vec[0] *= invLen; vec[1] *= invLen; vec[2] *= invLen; } // Scale the given vector static void scale (float v[3], float s) { v[0] *= s; v[1] *= s; v[2] *= s; } /* multLookAt -- Create a matrix to make an object, such as a camera, "look at" another object or location, from a specified position. Parameters: eye[x|y|z] Desired location of the camera object at[x|y|z] Location for the camera to look at up[x|y|z] Up vector of the camera Algorithm: The desired transformation is obtained with this 4x4 matrix: | [xaxis] 0 | | [up] 0 | | [-at] 0 | | [eye] 1 | Where 'xaxis', 'up' and 'at' are the new X, Y, and Z axes of the transforned object, respectively, and 'eye' is the input new location of the transformed object. Assumptions: The camera geometry is defined to be facing the negative Z axis. Usage: multLookAt creates a matrix and multiplies it onto the current matrix stack. Typical usage would be as follows: glMatrixMode (GL_MODELVIEW); // Define the usual view transformation here using // gluLookAt or whatever. glPushMatrix(); multLookAt (orig[0], orig[1], orig[2], at[0], at[1], at[2], up[0], up[1], up[2]); // Define "camera" object geometry here glPopMatrix(); Warning: Results become undefined as (at-eye) approaches coincidence with (up). */ static void multLookAt (float eyex, float eyey, float eyez, float atx, float aty, float atz, float upx, float upy, float upz) { float m[16]; float *xaxis = &m[0], *up = &m[4], *at = &m[8]; // Compute our new look at vector, which will be // the new negative Z axis of our transformed object. at[0] = atx-eyex; at[1] = aty-eyey; at[2] = atz-eyez; normalize (at); // Make a useable copy of the current up vector. up[0] = upx; up[1] = upy; up[2] = upz; // Cross product of the new look at vector and the current // up vector will produce a vector which is the new // positive X axis of our transformed object. cross (xaxis, at, up); normalize (xaxis); // Calculate the new up vector, which will be the // positive Y axis of our transformed object. Note // that it will lie in the same plane as the new // look at vector and the old up vector. cross (up, xaxis, at); // Account for the fact that the geometry will be defined to // point along the negative Z axis. scale (at, -1.f); // Fill out the rest of the 4x4 matrix m[3] = 0.f; // xaxis is m[0..2] m[7] = 0.f; // up is m[4..6] m[11] = 0.f; // -at is m[8..10] m[12] = eyex; m[13] = eyey; m[14] = eyez; m[15] = 1.f; // Multiply onto current matrix stack. glMultMatrixf (m); } static void display( void ) { glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity (); // View transform, place 'eye' at (0,1,5), and allow the scene // to rotate around its local Y axis in front of the eye. glTranslatef (0., -1., -5.); glRotatef (yrot, 0., 1., 0.); // Draw the target glColor3f (.7, .4, 1.); glPushMatrix (); glTranslatef (target[0], target[1], target[2]); gluSphere (quadSphere, .5, 24, 12); glPopMatrix (); glPushMatrix (); // Create transform so our next set of geometry will // "look at" the target. multLookAt (camera[0], camera[1], camera[2], target[0], target[1], target[2], 0., 1., 0.); // Now draw our "camera" which is just an orange cone // pointing at the target and a white cone indicating // the camera's local "up" direction. glRotatef (-90., 1., 0., 0.); glColor3f (1., 1., 1.); gluCylinder (quadCyl, .15, 0., .5, 8, 2); glRotatef (-90., 1., 0., 0.); glColor3f (1., .6, .4); gluCylinder (quadCyl, .25, 0., 1., 8, 2); glPopMatrix (); glutSwapBuffers(); } void reshape(int w, int h) { windowWidth=w; glViewport (0, 0, w, h); glMatrixMode (GL_PROJECTION); glLoadIdentity (); gluPerspective (50., (float)w/(float)h, 1., 20.); } static void mouse (int x, int y) { yrot = (float)x*360.f/(float)windowWidth - 180.f; glutPostRedisplay (); } static void init () { target[0] = target[1] = target[2] = 1.25f; camera[0] = camera[1] = camera[2] = 0.f; yrot = 0.f; glEnable (GL_DEPTH_TEST); { GLfloat pos[4] = {3., 5., 2., 1.}; GLfloat white[4] = {1., 1., 1., 1.}; GLfloat black[4] = {0., 0., 0., 0.}; /* Set up light1 */ glEnable (GL_LIGHTING); glEnable (GL_LIGHT1); glLightfv (GL_LIGHT1, GL_POSITION, pos); glLightfv (GL_LIGHT1, GL_DIFFUSE, white); glLightfv (GL_LIGHT1, GL_SPECULAR, black); /* ambient and diffuse will track glColor */ glEnable (GL_COLOR_MATERIAL); glColorMaterial (GL_FRONT, GL_AMBIENT_AND_DIFFUSE); glMaterialfv (GL_FRONT, GL_SPECULAR, black); } quadSphere = gluNewQuadric (); quadCyl = gluNewQuadric (); glutDisplayFunc (display); glutReshapeFunc (reshape); glutMotionFunc (mouse); glutKeyboardFunc (key); } void main(int argc, char** argv) { glutInit (&argc,argv); glutInitDisplayMode (GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); glutInitWindowSize (windowWidth=300,300); glutInitWindowPosition (0,0); glutCreateWindow ("Looking at an object"); init (); printf ("Left mouse button rotates the scene.\n"); printf ("Move the target object:\n"); printf ("\tq/Q\talong the X axis;\n"); printf ("\tw/W\talong the Y axis;\n"); printf ("\te/E\talong the Z axis.\n"); printf ("Move the camera object:\n"); printf ("\ta/A\talong the X axis;\n"); printf ("\ts/S\talong the Y axis;\n"); printf ("\td/D\talong the Z axis.\n"); printf ("Any other key exits.\n"); glutMainLoop (); }