Maximize MenuMinimize Menu

 

 

Back | Home

Creating 3D interactive Worlds

with OpenGL GLUT

 

HOW IT WORKS

Now we will take a look at exactly how our OpenGL GLUT application Creating 3D Interactive Worlds works.


First, the headers are included.

#include <windows.h>
#include <gl\gl.h>
#include <gl\glut.h>
#include <gl\glu.h> // GLU extension library - already in Pelles C

Next, various material and lighting properties are set.

// material and lighting properties
float materialAmbient[]={0.3, 0.2, 0.2, 1.0};
float materialDiffuse[]={0.9, 0.1, 0.1, 1.0};
float materialSpecular[]={0.0, 1.0, 1.0, 0.5};
float lightAmbient[]= {0.5, 0.5, 1.5, 1.0};
float lightDiffuse[]= {0.9, 0.9, 0.9, 1.0};
float lightSpecular[]={0.0, 0.0, 0.0, 1.0};
float lightPosition[]={1.0, 1.0, 1.0, 0.0};

Now the function prototypes section.

void init(void);
void display(void);
void keyboard(unsigned char, int, int);
void resize(int, int);

An integer declaration for depth testing.

int is_depth; // depth testing flag

The GLUT library is initialized, display mode and keyboard.

int main (int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(600, 600);
glutInitWindowPosition(40, 40);
glutCreateWindow("3D Interactive World");
init();
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);


//keep the aspect ratio constant by trapping the window resizes */

glutReshapeFunc(resize);

glutMainLoop();
return 0;
}

Amongst other states, Depth Testing is set here with glEnable(GL_DEPTH_TEST) Depth Testing is also known as z-buffering and is basically what determines what objects are in front of what other objects. Without it, it's not a good 3D world, objects crash through each other without intersecting, objects may show in front when they are behind, etc.

void init(void)
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glEnable(GL_DEPTH_TEST);
is_depth = 1;
glMatrixMode(GL_MODELVIEW);

// material and lighting properties

glEnable(GL_POINT_SMOOTH);
glEnable(GL_LINE_SMOOTH);
glLightfv(GL_LIGHT0,GL_AMBIENT,lightAmbient);
glLightfv(GL_LIGHT0,GL_DIFFUSE,lightDiffuse);
glLightfv(GL_LIGHT0,GL_POSITION,lightPosition);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,materialAmbient);
glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,materialDiffuse);
glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,materialSpecular);
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 20.0);

}

void display(void)
{
if (is_depth)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
else
glClear(GL_COLOR_BUFFER_BIT);
/* draw the ground */
glBegin(GL_QUADS);
//glColor3f(0.2f, 0.2f, 0.2f);
glVertex3f(-100.0, -50.0, -100.0);
//glColor3f(0.4f, 0.4f, 0.4f);
glVertex3f(-100.0, -50.0, 100.0);
//glColor3f(0.6f, 0.6f, 0.6f);
glVertex3f(100.0, -50.0, 100.0);
//glColor3f(0.8f, 0.8f, 0.8f);
glVertex3f(100.0, -50.0, -100.0);
glEnd();

Tetrahedron

Hexahedron


Octahedron

Dodecahedron

Icosahedron

Here we draw some polyhedrons, my favorite 5, the 5 platonic solids (or regular polyhedra) - Tetrahedron, Hexahedron, Octahedron, Dodecahedron, and Icosahedron.

First we draw a couple polyhedra at our current position. Then we save our position in space with glPushMatrix(), then we start translating around and drawing objects. Finally we return to our old position with glPopMatrix()

// Draw stuff here
glutSolidIcosahedron();
glutWireCube(10.0);

glPushMatrix(); //save the current matrix
glTranslatef(10.0, 0.0, 0.0); glutSolidDodecahedron();
glTranslatef(-20.0, 0.0, 0.0); glutSolidOctahedron();
glTranslatef(10.0, 10.0, 0.0); glutSolidCube(1.0);
glTranslatef(0.0, -20.0, 0.0); glutSolidTetrahedron();


glPopMatrix(); //return the previous matrix


glutSwapBuffers();
}

Here is where all of the Keyboard navigation occurs. A big switch statement decides how we are going to move depending on what keys are pressed.


Keyboard controls used:
Yaw, Roll, Pitch, North, South, East, West, Up, and Down


void keyboard(unsigned char key, int x, int y)

{
/* Keyboard controls:

"n": move north
"s": move south
"e": move east
"w": move west
"t": toggle depth-testing

"y": yaw
"p": pitch
"r": roll

"u": move up
"d": move down

*/
switch (key)
{

case 'y': //yaw
case 'Y':
glRotatef(10.0, 0.0, 1.0, 0.0);
break;

case 'p': //pitch
case 'P':
glRotatef(10.0, 1.0, 0.0, 0.0);
break;

case 'r': //roll
case 'R':
glRotatef(10.0, 0.0, 0.0, 1.0);
break;

case 'w':
case 'W':
glTranslatef(5.0, 0.0, 0.0);
break;

case 'e':
case 'E':
glTranslatef(-5.0, 0.0, 0.0);
break;

case 'n':
case 'N':
glTranslatef(0.0, 0.0, 5.0);
break;

case 's':
case 'S':
glTranslatef(0.0, 0.0, -5.0);
break;

case 'd':
case 'D':
glTranslatef(0.0, 5.0, -0.0);
break;

case 'u':
case 'U':
glTranslatef(0.0, -5.0, 0.0);
break;

case 't':
case 'T':
if (is_depth)
{
is_depth = 0;
glDisable(GL_DEPTH_TEST);
}
else
{
is_depth = 1;
glEnable(GL_DEPTH_TEST);
}
}

 

Various display settings and matrix modes are set here, including gluPerspective().


display();
}

void resize(int width, int height)
{
if (height == 0) height = 1;

glMatrixMode(GL_PROJECTION);
glLoadIdentity();

// divide width by height to get aspect ratio
gluPerspective(45.0, width / height, 1.0, 400.0);

// set initial position
glTranslatef(0.0, 0.0, -100.0); //south 100 units from origin

glMatrixMode(GL_MODELVIEW);
}


//---------------------------------------------------------------------


Back


  ©Copyright TrajectoryLabs.com. All Rights Reserved.