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();
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 |