GLUT Tutorials 6: GLUT Scene Roaming

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;
}

Keywords: Fragment

Added by Pottsy on Thu, 21 May 2020 04:04:21 +0300