==============================================================================
C-Scene Issue #05
A Quick OpenGL Tutorial
Platform: Multi-platform
Will Weisser
==============================================================================
Welcome to my OpenGL tutorial! Recently, with the appearance of
high-performance 3D graphics cards on the PC, 3D applications are no longer
delegated to the realm of the expensive custom workstation. For a C
programmer, this means more than games -- 3D is already being used in
hundreds of application areas which previously were somewhat...flat.
The de-facto standard for a 3D api for many years was OpenGL, originally made
by SGI. Unfortunetly, when it came time to port OGL over to the PC platform
to take advantage of the new accelerated graphics cards, Microsoft was hard
at work at it's own 3D standard--Direct3D. The result was that MS dragged its
feet somewhat and released a somewhat shoddy software-only port of OpenGL on
Windows 95. SGI also released a software-only version which takes advantage of
acceleration techniques such as the MMX instruction set, and many card
manufactures (such as those that use the 3Dfx chipset) provide their own
drivers for interfacing with their boards. Unfortunetly, Microsoft has made
it clear by their actions that Direct3D will be the only api they will
support for Windows 95 (and the upcoming Windows 98).
So where does that leave us, the development community? Well, you could learn
Direct3D...the process of which has several drawbacks: Firstly, Direct3D is by
far the most horridly designed 3D api that has ever existed. Also, since it is
built on top of DirectDraw, you must also learn that library before you can
even begin D3D work. In addition, if you don't know how to interface to COM
libraries (which in itself is no joy from C), that's another learning curveball
thrown your way. Finally, there is the obvious fact that Direct3D only works
for Win95, so cross-platform development is out of the question. If you want
the full story on the horrors of Direct3D, you can check out a D3D tutorial at
http://www.wksoftware.com/publications/d3dim.html.
Anyway, this tutorial is intended for C (or C++) programmers who have a
moderate to strong grasp of the language. There is no 3D experience required
to learn OpenGL, although it could help make some of the concepts clearer.
One of the nice things about OpenGL is that it's easy to use -- the interface
is straightforward with no excess baggage. Likewise rather than use COM to
provide an object-oriented paradigm in both C and C++, OpenGL is implemented as
C functions which can be organized in any manner you see fit. There are good
C++ encapsulations of OpenGL availible, but in this tutorial I'm just going
over the basics, so I won't hide the interface. Now on that note, lets get
started.
I. Introduction To OpenGL
OK, I assume if you're still here then you're hyped up to begin learning
OpenGL. First off, you have to get the libraries...
OpenGL should be availible on whatever platform you happen to be on. The
libraries and headers for Microsoft's version comes with Visual C++, or you can
download them from Microsoft's site. Alternativly, you can hunt around for
SGI's drivers at http://www.sgi.com/. If you're running Linux, I'd suggest
getting Mesa. It's availible for free at sunsite
(ftp://sunsite.unc.edu/pub/packages/development/graphics/mesa/). Whichever OGL
library you get, you're also going to need some sort of windowing system to
support it. For these examples I'm going to be using the GLUT, or OpenGL
Utility Toolkit
(ftp://sunsite.unc.edu/pub/packages/development/graphics/glut/). GLUT's main
job is to provide a window to draw your OpenGL code into. GLUT is also
portable, which means you can compile the same code for both Win95 and
X-Windows.
Now that that's out of the way, lets go on to:
/**********************************************************************/
/******************************************/
/* A Very Simple OpenGL Example! */
/******************************************/
/* this code just creates a window and draws a rectangle in it */
#include <windows.h> /* obviously change this to your native library
if you're compiling under unix */
#include <gl\gl.h>
#include <gl\glut.h>
void init(void);
void display(void);
int main (int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(250, 250);
glutInitWindowPosition(100, 100);
glutCreateWindow("My First OpenGL Application");
init();
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
void init(void)
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glColor3f(0.0, 0.0, 1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-10.0, 10.0, -10.0, 10.0, -10.0, 10.0);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glRectf(-5.0, 5.0, 5.0, -5.0);
glutSwapBuffers();
}
/**********************************************************************/
Lets go through this step by step:
First, I called the glutInit function, which provides general initialization
for the GLUT library:
int main (int argc, char **argv)
{
glutInit(&argc, argv);
Next I initialize the display mode:
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
This tells OpenGL that I want a double buffered window, with RGB color.
The next few lines create the window:
glutInitWindowSize(250, 250);
glutInitWindowPosition(100, 100);
glutCreateWindow("My First OpenGL Application");
As you can see, with GLUT this is fairly straightforward.
Now it's time to initialize OpenGL. Here's the code:
void init(void)
{
glClearColor(0.0, 0.0, 0.0, 0.0); /* set the background
(clearing) color to
RGB(0,0,0) -- black */
glColor3f(0.0, 0.0, 1.0); /* set the foreground color
to blue */
glMatrixMode(GL_PROJECTION); /* Initialize the matrix
state */
glLoadIdentity();
glOrtho(-10.0, 10.0, -10.0, 10.0, -10.0, 10.0);
}
In OpenGL, matrices are used to manage the view. There are two matrix modes,
projection and modelview. Projection is used to set up the viewport and
clipping boundry, while modelview is used to rotate, translate and scale
objects quickly.
Lets take a look at these two lines:
glLoadIdentity();
glOrtho(-10.0, 10.0, -10.0, 10.0, -10.0, 10.0);
glLoadIdentity() loads the identity matrix into the current matrix state (in
this case the projection matrix). You can consider this the resetting
matrix...it resets everything back to zero. Next comes the call to glOrtho.
This function sets up a clipping volume. You can think of a clipping volume as
a box in which your drawing commands are rendered. As the viewer, we are
positioned outside the box, looking in the front. What we see is whatever
is inside the box, projected onto the flat surface that is the side.
Anything outside the box is invisible. The glOrtho function creates an
orthographic view--that is, one with no perspective. We'll get to perspective
drawing later in the tutorial.
The arguments for glOrtho are as follows:
void glOrtho(double left, double right, double bottom, double top,
double near, double far);
Now, lets continue with the application:
glutDisplayFunc(display);
glutMainLoop();
The first function sets the function that GLUT will use whenever it needs to
update the view. We then call glutMainLoop() which actually runs the program.
From this point on our work is done; GLUT will handle the details of managing
the window and calling our painting function to display it.
Here is the display function again:
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glRectf(-5.0, 5.0, 5.0, -5.0);
glutSwapBuffers();
}
The first thing we do is call glClear with GL_COLOR_BUFFER_BIT parameter.
This will clear the window with the color we specified earlier using
glClearColor. Next, we actually draw our rectangle, using the glRectf
function.
Now's the time I should bring up something about OpenGL
function calls -- they often come in different forms. For example,
take glColor, which sets the current foreground color. This function has
several prototypes, for example:
glColor3f(float, float, float);
glColor4f(float, float, float, float);
glColor3d(double, double, double);
glColor3i(int, int, int);
etc, etc, etc.
As you can see, OpenGL functions are usually formatted like this:
gl Color 3 f
However, even though most OpenGL functions can accept any type, it's usually
best to pass floats. OpenGL uses floating point values for all its internal
calculations, so passing any other type is a waste of time since OGL will
just convert it back to floating point anyway.
The next function, glutSwapBuffers(), swaps the back buffer to the screen
buffer. In double-buffered mode, the drawing commands do not draw to the
screen. Rather, they draw to an offscreen buffer. Once you are done drawing,
you copy the entire back buffer to the screen at once, thus producing smooth
animation. Of course, in this simple example there is no animation, but
without a double buffer even moving the window around the screen will cause the
rectangle to flicker. Besides, it's good to get into the habit of producing
smooth graphics!
OK, now feel free to copy this program into an editor, compile it, and run it.
Note you will have to link with whatever libs your version of OpenGL has
provided, as well as the GLUT library. Under linux you will also probably
have to link the X Window libraries such as libX11.a.
Congratulations! You are now an OpenGL Programmer! But I know what you're
saying..."Where are the 3D graphics? You think I'm reading this junk to learn
how to draw a stupid square?" Well, since you're so impatient, lets move on
to creating 3D worlds with OpenGL...
II. Points, Lines, and Polygons
Before we start drawing 3D objects, lets quickly go over some fundamentals.
You will find drawing to a 3D canvas is in fact very similar to plain old 2D
applications. This is because OpenGL uses a coodinate system called the
Cartesian plane. The difference here is that instead of having two axis which
stretch horizontally and vertically, we add a third axis, the z (or depth)
axis. You can think of this as a line which runs through the origin (0,0 on
a Cartesian coordinate system), going in the direction from away from you to
straight towards you (in OpenGL, the positive z-axis always points towards
you, while the negative points away). Using this system, we can represent a
point in 3D space, called a "vertex", with three coordinites, representing x,
y, and z. For example:
(0,0,0) <-- The origin, the center of our defined space.
(2,0,4) <-- 2 units to the right, 4 units towards us, on the center of the
y-axis.
(3,-4,-2) <-- 3 units to the right, 4 units down, and 2 units away from us.
Got the hang of it? Then lets plot some points with OpenGL. We can use the
function glVertex to specifiy vertices, flanked by calls to glBegin and glEnd:
glBegin(GL_POINTS); /* We want to draw points */
glVertex3f(2.0, 0.0, 4.0); /* Specify a couple of vertices */
glVertex3f(3.0, -4.0, -2.0);
glEnd(); /* End points */
As you can see, glBegin tells OpenGL we want to start drawing (as well as WHAT
we want to start drawing), and glEnd tells it to stop. The great thing about
OGL's method of 3D drawing is it's flexibility -- lets say we want to draw some
lines:
glBegin(GL_LINES); /* lets do some lines now */
glVertex3f(6.0, 4.0, 2.0); /* here's one */
glVertex3f(2.0, -4.0, 3.3);
glVertex3f(5.0, 8.0, 8.0); /* here's another */
glVertex3f(-4.7, 5.0, -3.0);
glVertex3f(0.0, 0.0, 0.0); /* and another! */
glVertex3f(6.0, -1.0, -7.0);
glEnd();
Note that we now have one line for every two vertices. If you specify an odd
number, the last vertex is ignored.
Now lets do some shapes. OpenGL specifies 6 different polygon primitives:
GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS, GL_QUAD_STRIP, and
GL_POLYGON. Triangle and quad strips are shortcuts for building polygons next
to each other, and likewise a triangle fan is a group of triangles that share
a center point. GL_POLYGON can specify a general polygon with any number of
vertices. The one you should use most often is GL_TRIANGLES, since most
graphic accelerators are optimized for triangle operations. Here's an
example of a generic triangle:
glBegin(GL_TRIANGLES);
glVertex3f(-3.0, -3.0, 2.0);
glVertex3f(3.0, -3.0, -1.0);
glVertex3f(0.0, 3.0, 4.0);
glEnd();
See? Nothing to it!
Now, lets take what we've learned so far and draw some 3D using OpenGL. As
you can see, the following program bears more than a passing resemblence to
the previous one (GLUT is so nice that way), with some changes to the
display() function. One thing you will notice is that I change the current
color with glColor before specifiying some of the vertices. When OpenGL sees
a polygon with vertices that have different colors, it draws the figure by
smoothly shading from one color to the next. In this example I've created an
abstract shape made out of one square surrounded by four triangles. One
point of the triangles is red, while the other two are blue. This creates a
smoothing purple effect across the face of the triangle.
I'm also using this example to demonstrate some of the UI routines that GLUT
uses. In this case we are going to be using the function glutKeyboardFunc().
This function defines a callback handler that will be called whenever a key
is pressed while our window has focus.
/**********************************************************************/
/******************************************/
/* Example 2: Drawing in 3D */
/******************************************/
#include <windows.h>
#include <gl\gl.h>
#include <gl\glut.h>
void init(void);
void display(void);
void keyboard(unsigned char, int, int);
int main (int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(600, 600);
glutInitWindowPosition(50, 50);
glutCreateWindow("A 3D Object");
init();
glutDisplayFunc(display);
glutKeyboardFunc(keyboard); /* set keyboard handler */
glutMainLoop();
return 0;
}
void init(void)
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-15.0, 15.0, -15.0, 15.0, -15.0, 15.0);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_QUADS);
glColor3f(0.0, 0.0, 1.0); /* center square */
glVertex3f(-3.0, -3.0, 0.0);
glVertex3f(3.0, -3.0, 0.0);
glVertex3f(3.0, 3.0, 0.0);
glVertex3f(-3.0, 3.0, 0.0);
glEnd();
glBegin(GL_TRIANGLES);
glColor3f(1.0, 0.0, 0.0); /* now draw the four triangles */
glVertex3f(0.0, 6.5, 0.0);
glColor3f(0.0, 0.0, 0.9f);
glVertex3f(-3.0, 3.0, 0.0);
glVertex3f(3.0, 3.0, 0.0);
glColor3f(0.0, 0.0, 0.9f);
glVertex3f(-3.0, -3.0, 0.0);
glVertex3f(-3.0, 3.0, 0.0);
glColor3f(1.0, 0.0, 0.0);
glVertex3f(-6.5, 0.0, 0.0);
glColor3f(1.0, 0.0, 0.0);
glVertex3f(0.0, -6.5, 0.0);
glColor3f(0.0, 0.0, 0.9f);
glVertex3f(3.0, -3.0, 0.0);
glVertex3f(-3.0, -3.0, 0.0);
glColor3f(1.0, 0.0, 0.0);
glVertex3f(6.5, 0.0, 0.0);
glColor3f(0.0, 0.0, 0.9f);
glVertex3f(3.0, 3.0, 0.0);
glVertex3f(3.0, -3.0, 0.0);
glEnd();
glutSwapBuffers();
}
void keyboard(unsigned char key, int x, int y)
{
/* this is the keyboard event handler
the x and y parameters are the mouse
coordintes when the key was struck */
switch (key)
{
case 'u':
case 'U':
glRotatef(3.0, 1.0, 0.0, 0.0); /* rotate up */
break;
case 'd':
case 'D':
glRotatef(-3.0, 1.0, 0.0, 0.0); /* rotate down */
break;
case 'l':
case 'L':
glRotatef(3.0, 0.0, 1.0, 0.0); /* rotate left */
break;
case 'r':
case 'R':
glRotatef(-3.0, 0.0, 1.0, 0.0); /* rotate right */
}
display(); /* repaint the window */
}
/**********************************************************************/
Note that I use the glRotate function to rotate the view when the u, d, l, or
r keys are pressed; don't worry, we haven't gone over this yet. I'll cover it
in the next section, for now I put it in to illustrate the 3D nature of our
shape. You may want to play around with this demo before continuing on to the
next section. What else can you draw? What happens to the shading in the demo
if you call glShadeModel(GL_FLAT)? Once you feel comfortable working with 3D
space, we can move on to the next section...
III. Perspective, Animation, and Depth Testing
OK, enough teasing! Now that you know how to draw polygons in OpenGL, you can
do anything! Lets move on to some more advanced tricks to make really
impressive graphical applications.
First off, a while back I promised you perspective...well, here it is. In
case you're wondering, perspective means that objects recede, or get smaller
with distance. In OpenGL the only thing required to use perspective is to set
up the clipping volume for that operation. This can sometimes be tricky,
since instead of a cube, a perspective clipping volume is actually sort of a
truncated pyramid, called a frustum. The typical OGL function to do this is
glFrustum, shown here:
void glFrustum(double left, double right, double bottom, double top,
double near, double far);
In this case, near and far are the distances to the front and back clipping
planes. This function may look simple at first, but it gets tricky once you
start dealing with windows that can be resized, etc. A far better solution
is gluPerspective:
void gluPerspective(double fovy, double aspect, double near, double far);
The last two arguments remain the same as above, but what are aspect and fovy?
FOVY is the Field Of View, and it specifies the angle which represents how
much the viewer can see...somewhat like changing to a wide-angle lens in
photography. Aspect is the aspect ratio of width/height in the window. Now I
know what you're thinking: "Are you nuts? Fovy? Aspect? I'm supposed to
understand this?" But don't worry; you'll see in the example program in this
section why gluPerspective sets up a viewing volume so easily. Also note that
the function's name begins with glu, not gl. This is an indicator that
gluPerspective is not a part of the regular OpenGL library, but rather an
extension which remains a part of the GL standard. Just remember that when
using any function beginning with glu, you must #include <gl\glu.h>, and link
with the appropriate library.
Well, if you followed that, you now have a nice perspective view to draw into.
Now lets make the renderings themselves more interesting by adding motion.
If you've ever seen any kind of documentary on cartoons and so forth, you're
familiar with the concept of animation. You just take many slightly different
static drawings and switch them very fast in front of the viewer to produce a
motion effect. This is the easy part; we're already drawing several frames a
second into our window. The hard part is moving our pictures so they make
sense in relation to each other. In practice this involves a little math.
For example, if you have an object at point x, you can move said object over
4 units if you add 4 to all the x coordinates of the vertices that make up the
object (whew!). Likewise, if you know how to rotate each individual vertex
around a circle (using the cosine and sine to determine the x and y
coordinites), you can rotate the entire object in this manner. The problem
with these types of operations is they're slow...it's easier to compute all
the coordinate positions at once using a matrix. Matrices are kind of like
tables that can encapsulate these types of operations. I'm not going to go
into detail about it here, since OpenGL contains built in support for handling
matrices. The problem is they don't always do what you want; a transformation
matrix, when applied, will transform the *entire* scene, not just the object
you wanted to move! There are some neat tricks you can use involving the
matrix stack to put any combination of transforms into a matrix, but space
will not permit me to discuss that here :(. In the meantime we can use
matrices to move our objects at times when we want the entire scene to move
as a unit.
Here are the functions in OpenGL which deal with matrices:
void glLoadIdentity(void);
You've seen this one before...this function loads the "identity" matrix into
the current matrix. This has the effect of resetting everything back to its
original position, i.e. an object drawn centered at (0,0,0) will appear in
the center of the screen.
void glTranslatef(float x, float y, float z);
This function translates (moves) the entire scene forward, left and up the
specified amounts. Use negative values to translate in the other direction.
void glRotatef(float angle, float x, float y, float z);
Again, this function rotates the entire scene. The way this is called might
be a little confusing; the amount of rotation is determined by angle (0-359),
and the scene is rotated around the vector specified by x, y, and z.
void glScalef(float x, float y, float z);
This is a more rarely-used function; it scales (makes larger or smaller) the
scene by the specified factor. For example, scaling by a factor of 2.0 makes
the scene appear twice as large, whereas a factor of 1.0 does nothing and a
factor of 0.5 will halve the size. You can scale each axis independantly to
produce a squishing or stretching effect.
OK, so now you (hopefully) know how to move stuff around using OpenGL, lets
do one more thing: depth testing. This is the process of determining what
falls in front of what...in other words, is the house in front of the dog or
is the dog in front of the house? This may sound trivial at first, but in
order to get realistic looking scenes we usually use something called a
z-buffer, which tests each pixel to see if it should is unhidden and should
therefore be drawn. This would normally be a big to-do, but OpenGL is nice
enough to handle all the details for us. Be warned though: unless you have a
video accelerator with a lot of video memory, z-buffering will slow down
rendering immensely. Z-buffers can make for really cool effects (such as
objects passing through other objects), but watch out for the performance hit.
That being said, applying a z-buffer to your scene is easy; first, put a call
to glEnable in your initialization, like so:
glEnable(GL_DEPTH_TEST);
Then, clear your z-buffer at the end of every frame. You can do this at the
same time you clear your drawing window, like so:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Simple, eh? Well now we have depth-cued perspective motion...in other words,
your resume is stacked and you're rearing to go! Lets continue on to the
final example:
/**********************************************************************/
/********************************************************************/
/* Example 3: A fully interactive 3D world with OpenGL */
/********************************************************************/
#include <windows.h>
#include <gl\gl.h>
#include <gl\glut.h>
#include <gl\glu.h> /* GLU extention library */
void init(void);
void display(void);
void keyboard(unsigned char, int, int);
void resize(int, int);
void drawcube(int, int, int);
int is_depth; /* depth testing flag */
int main (int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(600, 600);
glutInitWindowPosition(40, 40);
glutCreateWindow("The Cube World");
init();
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
/* this time we're going to keep the aspect ratio
constant by trapping the window resizes */
glutReshapeFunc(resize);
glutMainLoop();
return 0;
}
void init(void)
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glEnable(GL_DEPTH_TEST);
is_depth = 1;
glMatrixMode(GL_MODELVIEW);
}
void display(void)
{
if (is_depth)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
else
glClear(GL_COLOR_BUFFER_BIT);
/* draw the floor */
glBegin(GL_QUADS);
glColor3f(0.2f, 0.2f, 0.2f);
glVertex3f(-100.0, 0.0, -100.0);
glColor3f(0.4f, 0.4f, 0.4f);
glVertex3f(-100.0, 0.0, 100.0);
glColor3f(0.6f, 0.6f, 0.6f);
glVertex3f(100.0, 0.0, 100.0);
glColor3f(0.8f, 0.8f, 0.8f);
glVertex3f(100.0, 0.0, -100.0);
glEnd();
/* draw 12 cubes with different colors */
drawcube(75, 57, 2);
drawcube(-65, -12, 3);
drawcube(50, -50, 1);
drawcube(-56, 17, 2);
drawcube(67, 12, 3);
drawcube(-87, 32, 1);
drawcube(-26, 75, 2);
drawcube(57, 82, 3);
drawcube(-3, 12, 1);
drawcube(46, 35, 2);
drawcube(37, -2, 3);
glutSwapBuffers();
}
void keyboard(unsigned char key, int x, int y)
{
/* This time the controls are:
"a": move left
"d": move right
"w": move forward
"s": move back
"t": toggle depth-testing
*/
switch (key)
{
case 'a':
case 'A':
glTranslatef(5.0, 0.0, 0.0);
break;
case 'd':
case 'D':
glTranslatef(-5.0, 0.0, 0.0);
break;
case 'w':
case 'W':
glTranslatef(0.0, 0.0, 5.0);
break;
case 's':
case 'S':
glTranslatef(0.0, 0.0, -5.0);
break;
case 't':
case 'T':
if (is_depth)
{
is_depth = 0;
glDisable(GL_DEPTH_TEST);
}
else
{
is_depth = 1;
glEnable(GL_DEPTH_TEST);
}
}
display();
}
void resize(int width, int height)
{
if (height == 0) height = 1;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
/* note we divide our width by our height to get the aspect ratio */
gluPerspective(45.0, width / height, 1.0, 400.0);
/* set initial position */
glTranslatef(0.0, -5.0, -150.0);
glMatrixMode(GL_MODELVIEW);
}
void drawcube(int x_offset, int z_offset, int color)
{
/* this function draws a cube centerd at (x_offset, z_offset)
x and z _big are the back and rightmost points, x and z _small are
the front and leftmost points */
float x_big = (float)x_offset + 5;
float z_big = (float)z_offset + 5;
float x_small = (float)x_offset - 5;
float z_small = (float)z_offset - 5;
switch(color)
{
case 1:
glColor3f(1.0,0.0,0.0);
break;
case 2:
glColor3f(0.0,1.0,0.0);
break;
case 3:
glColor3f(0.0,0.0,1.0);
break;
}
glBegin(GL_QUADS);
glVertex3f(x_small,10.0,z_big); /* front */
glVertex3f(x_small,0.0,z_big);
glVertex3f(x_big,0.0,z_big);
glVertex3f(x_big,10.0,z_big);
glVertex3f(x_big,10.0,z_small); /* back */
glVertex3f(x_big,0.0,z_small);
glVertex3f(x_small,0.0,z_small);
glVertex3f(x_small,10.0,z_small);
glVertex3f(x_big,10.0,z_big); /* right */
glVertex3f(x_big,0.0,z_big);
glVertex3f(x_big,0.0,z_small);
glVertex3f(x_big,10.0,z_small);
glVertex3f(x_small,10.0,z_small); /* left */
glVertex3f(x_small,0.0,z_small);
glVertex3f(x_small,0.0,z_big);
glVertex3f(x_small,10.0,z_big);
glVertex3f(x_small,10.0,z_big); /* top */
glVertex3f(x_big,10.0,z_big);
glVertex3f(x_big,10.0,z_small);
glVertex3f(x_small,10.0,z_small);
glVertex3f(x_small,0.0,z_small); /* bottom */
glVertex3f(x_big,0.0,z_small);
glVertex3f(x_big,0.0,z_big);
glVertex3f(x_small,0.0,z_big);
glEnd();
}
/**********************************************************************/
If you know anything about 3D graphics, you'll probably notice this program
is horrendously inefficient. This can easily be changed with OpenGL, but I
don't have time to explain how...I leave it as an exercise to the reader
(that's what us tutorial people say when we don't feel like doing something
:P).
Go ahead and compile this and play around with it...you'll notice there's no
collision detection and no way to turn around. This is only the tip of the
iceburg as far as OpenGL goes; in fact it's almost embarrassing how much I
left out! If you want to find out more about projection, texture mapping,
colors, lighting, tesselation, nurbs, fog, stenciling, quadrics, and more, I'd
reccomend the following books:
The OpenGL Superbible
The Complete Guide to OpenGL Programming for Windows NT and Windows 95
By Richard S. Wright Jr. and Michael Sweet
Waite Group Press
ISBN 1-57169-073-5
A great book for beginners, which also covers native Win32 graphics with
OpenGL...highly reccomended!
The OpenGL Programming Guide, Second Edition
The Official Guide to Learning OpenGL, Version 1.1
By Mason Woo, Jackie Neider and Tom Davis
Addison-Wesley Developers Press
ISBN 0-201-46138-2
Contains *everything* you ever wanted to know about OpenGL 1.1, although it
may be a little "thick." Perhaps better used as a reference, but contains
invaluable info about the GLUT.
Also check out http://www.opengl.org for the latest OGL info & software.
Lastly, if you ever want to contact me, I'm availible at
kased811@ix.netcom.com. I'm afraid I can't offer freelance OpenGL guidance,
but if you want to talk about the contemplation of your navel, I'm all ears
:P. In the meantime, happy coding and good luck with OpenGL!
This page is Copyright © 1998 By
C Scene. All Rights Reserved