Blog from:http://blog.csdn.net/xie_zi/article/details/1911997
Let's take a look at a good example of using keyboard control.In this chapter we will build an application.This program draws a small world of snowmen.And we'll use the arrow keys to move the camera (that is, to move the viewpoint and roam through the scene).Left and right arrow keys, rotate the camera around the y-axis, up and down arrow keys, move the camera forward and backward.
The code for this example is shown below.First let's work on the initial state.
#include <math.h> #include <GL/glut.h> #include <stdlib.h> static float angle=0.0,ratio; static float x=0.0f,y=1.75f,z=5.0f; static float lx=0.0f,ly=0.0f,lz=-1.0f; static GLint snowman_display_list;
Notice that we include the math.h header file.We need to calculate the rotation angle.You'll see what the above variables mean later, but let's just describe them:
1:angle: The angle of rotation around the y-axis, which allows us to rotate the camera.
2:x,y,z: Camera position.
3:lx,ly,lz: A vector is used to indicate the direction of our line of sight.
4:ratio: The width/height ratio of the window.
5:snowman_display_list: An index of a snowman's display list.
Note: If you do not want to use a display list, you can also ignore it. This does not affect the tutorial.
Next, we use a common function to handle window sizes.The only difference is that the parameters to the function glutLookAt use variables instead of fixed values.The gluLookAt function provides a simple and intuitive way to set the camera position and orientation.It has three sets of parameters, each of which consists of three floating-point numbers.The first three parameters indicate the position of the camera, the second defines the direction in which the camera is looking, and the last set indicates the vector up, which is usually set to (0.0, 1.0, 0.0).That means the camera is not tilted.If you want to see that all objects are upside down, you can set it to (0.0, -1.0, 0.0).
The variables x,y,z mentioned above represent the camera position, so these three variables correspond to the first set of vectors in the function gluLookAt.The second set of parameters, the viewing direction, is obtained by adding the vector defining the line of sight to the camera position:
Look At Point=Line Of Sight+ Camera Position
void reShape(int w, int h) { // Prevent dividing by 0. if(h == 0) h = 1; ratio = 1.0f * w / h; // Reset the coordinate system before modifying glMatrixMode(GL_PROJECTION); glLoadIdentity(); //Set Viewport to Whole Window Size glViewport(0, 0, w, h); //Set Visual Space gluPerspective(45,ratio,1,1000); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(x, y, z, x + lx,y + ly,z + lz, 0.0f,1.0f,0.0f); }
Here we define the display list, draw the snowman, initialize the scene, and render the scene.
void drawSnowMan() { glColor3f(1.0f, 1.0f, 1.0f); //Draw body glTranslatef(0.0f ,0.75f, 0.0f); glutSolidSphere(0.75f,20,20); // Picture Head glTranslatef(0.0f, 1.0f, 0.0f); glutSolidSphere(0.25f,20,20); // Draw Eyes glPushMatrix(); glColor3f(0.0f,0.0f,0.0f); glTranslatef(0.05f, 0.10f, 0.18f); glutSolidSphere(0.05f,10,10); glTranslatef(-0.1f, 0.0f, 0.0f); glutSolidSphere(0.05f,10,10); glPopMatrix(); // Paint nose glColor3f(1.0f, 0.5f , 0.5f); glRotatef(0.0f,1.0f, 0.0f, 0.0f); glutSolidCone(0.08f,0.5f,10,2); }
Create Display List Number
GLuint createDL() { GLuint snowManDL; //Generate a display list number snowManDL = glGenLists(1); // Start showing list glNewList(snowManDL,GL_COMPILE); // call the function that contains // the rendering commands drawSnowMan(); // endList glEndList(); return(snowManDL); }
Here we set up a function to handle special key press messages.Use the left and right arrow keys to rotate the camera, that is, to change the line of sight.The up and down arrow keys move the camera forward and backward along the line of sight.
void inputKey(int key, int x, int y) { switch (key) { case GLUT_KEY_LEFT : angle -= 0.01f; orientMe(angle);break; case GLUT_KEY_RIGHT : angle +=0.01f; orientMe(angle);break; case GLUT_KEY_UP : moveMeFlat(1);break; case GLUT_KEY_DOWN : moveMeFlat(-1);break; }
The angle variable changes when we press the left and right arrow keys, and orientMe is called.This function will rotate the camera.The function moveMeFlat is responsible for moving the camera along a line of sight in the XZ plane.The orientMe function accepts a parameter angle and calculates an appropriate value for the X,Z of the line of sight.The new lx and lz are mapped on a unit circle of the XZ plane.So given an angle ang, the new values of lx and lz are:
Lx=sin(ang); Lz=cos(ang);
Just like we convert polar coordinates (ang, 1) into Euclidean geometric coordinates.Then we set a new camera orientation.Note: The camera has not moved, the camera position has not changed, only the direction of the line of sight has changed.
void orientMe(float ang) { lx = sin(ang); lz = -cos(ang); glLoadIdentity(); gluLookAt(x, y, z, x + lx,y + ly,z + lz, 0.0f,1.0f,0.0f); }
The next function is to manage moveMeFlat for camera movement.We want to move the camera along the line of sight.To accomplish this task, we add a small part of our sight to our current position.The new X,Z values are:
X=x+direction(lx)*fraction Z=z+direction*(lz)*fraction
Direction is 1 or -1, depending on whether we move forward or backward.This fraction accelerates visual implementation.We know (lx,lz) is a vector of the whole.So if fraction is a constant then the velocity of movement is a constant.Increase the fragment so we can move faster.The next steps are the same as the orientMe function.
void moveMeFlat(int direction) { x = x + direction*(lx)*0.1; z = z + direction*(lz)*0.1; glLoadIdentity(); gluLookAt(x, y, z, x + lx,y + ly,z + lz, 0.0f,1.0f,0.0f); }
The main function is as follows:
int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_RGBA | GLUT_DOUBLE); glutInitWindowPosition(100,100); glutInitWindowSize(640,360); glutCreateWindow("GLUT Tutorials Scene Rovering"); initScene(); glutSpecialFunc(inputKey); glutDisplayFunc(renderScene); glutIdleFunc(renderScene); glutReshapeFunc(reShape); glutMainLoop(); return 0; }
This section of the VC project you can download here ( glut4.zip ), as shown below
Here is my complete code
#include <math.h> #include <stdlib.h> #include <gl/glut.h> static float angle = 0.0, ratio; static float x = 0.0f, y = 1.75f, z = 5.0f; static float lx = 0.0f, ly = 0.0f, lz = -1.0f; static GLint snowman_display_list; void reShape(int width, int height) { // Prevent dividing by 0. if (height == 0) height = 1; ratio = 1.0f * width / height; //Reset the coordinate system before modifying glMatrixMode(GL_PROJECTION); glLoadIdentity(); //Set Viewport to Whole Window Size glViewport(0, 0, width, height); //Set Visual Space gluPerspective(45, ratio, 1, 1000); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(x, y, z,x + lx, y + ly, z + lz, 0.0f, 1.0f, 0.0f); } void drawSnowMan() { glColor3f(1.0f, 1.0f, 1.0f); //Draw body glTranslatef(0.0f, 0.75f, 0.0f); glutSolidSphere(0.75f, 20, 20); // Picture Head glTranslatef(0.0f, 1.0f, 0.0f); glutSolidSphere(0.25f, 20, 20); // Draw Eyes glPushMatrix(); glColor3f(0.0f, 0.0f, 0.0f); glTranslatef(0.05f, 0.10f, 0.18f); glutSolidSphere(0.05f, 10, 10); glTranslatef(-0.1f, 0.0f, 0.0f); glutSolidSphere(0.05f, 10, 10); glPopMatrix(); // Paint nose glColor3f(1.0f, 0.5f, 0.5f); glRotatef(0.0f, 1.0f, 0.0f, 0.0f); glutSolidCone(0.08f, 0.5f, 10, 2); } GLuint createDL() { GLuint snowManDL; //Generate a display list number snowManDL = glGenLists(1); // Start showing list glNewList(snowManDL, GL_COMPILE); // call the function that contains // the rendering commands drawSnowMan(); // endList glEndList(); return(snowManDL); } void initScene() { glEnable(GL_DEPTH_TEST); snowman_display_list = createDL(); } void renderScene(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //Draw a floor glColor3f(0.9f, 0.9f, 0.9f); glBegin(GL_QUADS); glVertex3f(-100.0f, 0.0f, -100.0f); glVertex3f(-100.0f, 0.0f, 100.0f); glVertex3f(100.0f, 0.0f, 100.0f); glVertex3f(100.0f, 0.0f, -100.0f); glEnd(); //Thirty-six snowmen were drawn for (int i = -3; i < 3; i++) { for (int j = -3; j < 3; j++) { glPushMatrix(); glTranslatef(i*10.0, 0, j * 10.0); glCallList(snowman_display_list); glPopMatrix(); } } glutSwapBuffers(); } void moveMeFlat(int direction) { x = x + direction*(lx)*0.1; z = z + direction*(lz)*0.1; glLoadIdentity(); gluLookAt(x, y, z,x + lx, y + ly, z + lz,0.0f, 1.0f, 0.0f); } void orientMe(float ang) { lx = sin(ang); lz = -cos(ang); glLoadIdentity(); gluLookAt(x, y, z,x + lx, y + ly, z + lz,0.0f, 1.0f, 0.0f); } void inputKey(int key, int x, int y) { switch (key) { case GLUT_KEY_LEFT: angle -= 0.01f; orientMe(angle); break; case GLUT_KEY_RIGHT: angle += 0.01f; orientMe(angle); break; case GLUT_KEY_UP: moveMeFlat(1); break; case GLUT_KEY_DOWN: moveMeFlat(-1); break; } } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_RGBA | GLUT_DOUBLE); glutInitWindowPosition(100,100); glutInitWindowSize(640,360); glutCreateWindow("GLUT Tutorials Scene Rovering"); initScene(); glutSpecialFunc(inputKey); glutDisplayFunc(renderScene); glutIdleFunc(renderScene); glutReshapeFunc(reShape); glutMainLoop(); return 0; }