Lab (8) - Viewing and Moving in a Scene

Objectives:
To learn about glLookAt function
To clear to create a simple scene and to move in the scene
To create more a complex scene

There are several different things you will do in this lab. If by any chance you didn't finish them, work on them on your own. You need to have the box with the two squares in it for an assignment I will give very soon.

Following is a program that creates a cube with sides of six different colors.

#include <cmath>
#include <stdlib.h>
#include <GL/glut.h>
typedef GLfloat point3[3];
double PI = 3.141592653;
point3 p[8]={
{0,0,0}, //black
{0,0,1}, //blue
{1,0,1}, //magenta
{1,0,0}, //red
{0,1,0}, //green
{0,1,1}, //green+blue
{1,1,1}, //white
{1,1,0} //yellow
};

void drawPoint(int i){
glVertex3fv(p[i]);
}
void drawFace(int i1,int i2,int i3,int i4){
glBegin(GL_POLYGON);
glColor3fv(p[i1]);
drawPoint(i1);
drawPoint(i2);
drawPoint(i3);
drawPoint(i4);
glEnd();
}


void myinit(void)
{

/* attributes */
glClearColor(1.0, 1.0, 1.0, 1.0); /* white background */
glColor3f(0.0, 0.0, 0.0); /* draw in black */
/* set up viewing */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1, 1, -1, 1,-10,10);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_DEPTH_TEST);
}
void drawCube(){
drawFace(1, 0,3,2);
drawFace(2,6, 5,1);
drawFace(7, 6, 2,3);
drawFace(3,0,4,7);
drawFace(4,5,6,7);
drawFace(5,4,0,1);
}

void display( void )
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); /*clear the window */
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Add the gluLookAt here

drawCube();
glFlush(); /* clear buffers */
}

void main(int argc, char** argv)
{
/* Standard GLUT initialization */
glutInit(&argc,argv);
glutInitDisplayMode (GLUT_SINGLE| GLUT_RGB|GLUT_DEPTH);

glutInitWindowSize(500,500); /* 500 x 500 pixel window */
glutInitWindowPosition(0,0); /* place window top left on display */
glutCreateWindow("Cube"); /* window title */
glutDisplayFunc(display); /* display callback invoked when window opened */
myinit(); /* set attributes */
glutMainLoop(); /* enter event loop */
}

Activity (1)
Cut and paste the program on your computer, compile, then run it.  You should get one of its sides, take that side as the front side.

In our last lab we used animation to rotate the cube.  This time we want to use the viewing to create a move in or around the box.  Here we will take a different approach.

Using gluLookAt Function The gluLookAt function provides an alternative to glTranslatef and glRotatef sequences for positioning the camera. It does not, however, change the "lens" (or projection matrix) used. Here's the documentation:

gluLookAt

NAME

gluLookAt -- define a viewing transformation 

C SPECIFICATION

void gluLookAt(GLdouble eyex,
               GLdouble eyey,
               GLdouble eyez,
               GLdouble centerx,
               GLdouble centery,
               GLdouble centerz,
               GLdouble upx,
               GLdouble upy,
               GLdouble upz)

PARAMETERS

eyex, eyey, eyez 
     Specifies the position of the eye point. 
centerx, centery, centerz 
     Specifies the position of the reference point. 
upx, upy, upz 
     Specifies the direction of the up vector. 

DESCRIPTION

gluLookAt creates a viewing matrix derived from an eye point, a reference point indicating the center of the scene, and an up vector. The matrix maps the reference point to the negative z axis and the eye point to the origin, so that, when a typical projection matrix is used, the center of the scene maps to the center of the viewport. Similarly, the direction described by the up vector projected onto the viewing plane is mapped to the positive y axis so that it points upward in the viewport. The up vector must not be parallel to the line of sight from the eye to the reference point. The matrix generated by gluLookAt postmultiplies the current matrix.

Activity (2)
Make a change in your program such that you create the same "isogonal" view of the box as shown below using the
gluLookAt function.  I have marked the location where you will add the call to the gluLookAt function.


iso1

Activity (3)
Use the gluLookAt function to determine the color of all sides.  Let's for now assume that the purple (magenta) is the front side.  Actually to display the color of the front side, you could use:
gluLookAt(0,0, 1 ,0,0,0,0,1,0);

Make a list for yourself here:
Front:  magenta         Back: .....................     Top: .......................      Bottom: ........................  Left: .........................,  and Right: ....................

Activity (4)

Use the above information and the gluLookAt to create the following view.  You can find this  by trying different things, but the best way is to figure  that out on  paper, then try to see if you have compute it correctly.

iso2

Conduct some experiments with gluLookAt by changing the top direction, changing the point you look at and so forth to how things work.

Activity (5)
Now that you have created the above views, you should know how the gluLookAt function works.  Let's see if we can create more complicated applications.  The following program is the one I used in class to demonstrate how the mouse and keyboard can be used to move in a scene.  The mouse clicks controls the rotation and the keyboard, x, X, y, Y, z, and Z control the movements.  The "r" key reset the x, y, and z you can change that as you wish.

/* Original code from Angle's textbook.  Modifications by Rahman Tashakkori
Rotating cube with viewer movement from Chapter 5 */

/* Cube definition and display similar to rotating--cube program */
/* We use the Lookat function in the display callback to point
the viewer, whose position can be altered by the x,X,y,Y,z, and Z keys.
The perspective view is set in the reshape callback */

#include <stdlib.h>
#include <GL/glut.h>


    GLfloat vertices[][3] = {{-1.0,-1.0,-1.0},{1.0,-1.0,-1.0},
    {1.0,1.0,-1.0}, {-1.0,1.0,-1.0}, {-1.0,-1.0,1.0},
    {1.0,-1.0,1.0}, {1.0,1.0,1.0}, {-1.0,1.0,1.0}};

    GLfloat colors[][3] = {{0.0,0.0,0.0},{1.0,0.0,0.0},
    {1.0,1.0,0.0}, {0.0,1.0,0.0}, {0.0,0.0,1.0},
    {1.0,0.0,1.0}, {1.0,1.0,1.0}, {0.0,1.0,1.0}};

void polygon(int a, int b, int c , int d)
{
    glBegin(GL_POLYGON);
        glColor3fv(colors[a]);
        glVertex3fv(vertices[a]);
        glVertex3fv(vertices[b]);
        glVertex3fv(vertices[c]);
        glVertex3fv(vertices[d]);
    glEnd();
}

void colorcube()
{
    polygon(2, 1, 0,3);
    polygon(6,2,3,7);
    polygon(3,0,4,7);
    polygon(1,2,6,5);
    polygon(4,5,6,7);
    polygon(5, 4, 0,1);
}


static GLfloat theta[] = {0.0,0.0,0.0};
static GLint axis = 2;
static GLdouble viewer[]= {0.0, 0.0, 5.0}; /* initial viewer location */

void display(void)
{

 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

/* Update viewer position in modelview matrix */

    glLoadIdentity();
    gluLookAt(viewer[0],viewer[1],viewer[2], 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

/* rotate cube */

    glRotatef(theta[0], 1.0, 0.0, 0.0);
    glRotatef(theta[1], 0.0, 1.0, 0.0);
    glRotatef(theta[2], 0.0, 0.0, 1.0);

 colorcube();
 glFlush();
    glutSwapBuffers();
}

void mouse(int btn, int state, int x, int y)
{
    if(btn==GLUT_LEFT_BUTTON && state == GLUT_DOWN) axis = 0;
    if(btn==GLUT_MIDDLE_BUTTON && state == GLUT_DOWN) axis = 1;
    if(btn==GLUT_RIGHT_BUTTON && state == GLUT_DOWN) axis = 2;
    theta[axis] += 2.0;
    if( theta[axis] > 360.0 ) theta[axis] -= 360.0;
    display();
}

void keys(unsigned char key, int x, int y)
{

/* Use x, X, y, Y, z, and Z keys to move viewer */

   if(key == 'x') viewer[0]-= 1.0;    //
   if(key == 'X') viewer[0]+= 1.0;  //
   if(key == 'y') viewer[1]-= 1.0;    //
   if(key == 'Y') viewer[1]+= 1.0;  //
   if(key == 'z') viewer[2]-= 1.0;    //
   if(key == 'Z') viewer[2]+= 1.0;   //
   if(key == 'r' || key == 'R')
   {
       theta[0] = theta[1] = theta[2] = 0.0;
       axis = 2;
       viewer[0] = viewer[1] = 0.0;
       viewer[2] =  5.0; /* initial viewer location */
    }
   display();
}

void myReshape(int w, int h)
{
 glViewport(0, 0, w, h);

/* Use a perspective view */

 glMatrixMode(GL_PROJECTION);
 glLoadIdentity();
    if(w<=h) glFrustum(-2.0, 2.0, -2.0 * (GLfloat) h/ (GLfloat) w,
       2.0* (GLfloat) h / (GLfloat) w, 2.0, 20.0);
    else glFrustum(-2.0, 2.0, -2.0 * (GLfloat) w/ (GLfloat) h,
       2.0* (GLfloat) w / (GLfloat) h, 2.0, 20.0);

/* Or we can use gluPerspective */

 /* gluPerspective(45.0, w/h, -10.0, 10.0); */

 glMatrixMode(GL_MODELVIEW);
}

void main(int argc, char **argv)
{
 glutInit(&argc, argv);
 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
 glutInitWindowSize(500, 500);
 glutCreateWindow("colorcube");
 glutReshapeFunc(myReshape);
 glutDisplayFunc(display);
    glutMouseFunc(mouse);
    glutKeyboardFunc(keys);
    glEnable(GL_DEPTH_TEST);
 glutMainLoop();
}

Try to move around and see how the mouse and keyboard are used with the gluLookAt and glFrustum to move in the scene.   If you don't know where you are (you are lost) remember the "r" key.   That resets all parameters to the one you started with.

Activity (6)
Now, this is the fun part.  Add two smaller cubes inside the cube you have created in the above activity.  The center of the new cubes are:
Cube 1:  (-0.5, 0, 0)
Cube 2:  (0.5 , 0, 0)

There are several ways to do this, but I recommend you use the glPushMatrix and glPopMatrix to make this more efficient.

cube2inside

Note that I got the above image as I crossed the front side into the box using z movements.  It is best that you have a small value for increment in x, y, and z to see this nicely.  I have used 0.1 instead of 1.0 given in the program.

Here is another view that shows the location of inside boxes better.

2

In Lab Questions:
Type your answers in a MS Word file or in an editor of your choice on CS, print a copy with your name on it, and submit that in the lab.

1. Explain how you can produce the following image in two different ways.  One should involve changing parameters in gluLookAt only.

b

You can check by making changes in your program to see whether your idea works or not.

2. What does the following code segment do?
    if(w<=h) glFrustum(-2.0, 2.0, -2.0 * (GLfloat) h/ (GLfloat) w,
       2.0* (GLfloat) h / (GLfloat) w, 2.0, 20.0);
    else glFrustum(-2.0, 2.0, -2.0 * (GLfloat) w/ (GLfloat) h,
       2.0* (GLfloat) w / (GLfloat) h, 2.0, 20.0);

The Post-lab for this lab is Assignment (7).