Tutorial: Introduction to OpenGL

Go to page << 1 2 >>

An Introduction to OpenGL 3D Programming Using Basic4GL

14-Nov-2003
Tom Mulgrew

Intro

Hello! And welcome to this set of tutorials, which are designed to take some of the mysticism out of 3D programming and OpenGL. If you're new to OpenGL or 3D in general, then these tutorials are intended for you, they assume no prior knowledge or experience with either. You will however need a little bit of programming knowledge to follow the examples (but you don't have to be a guru).

This tutorial uses Basic4GL. This is a BASIC programming language with OpenGL support, designed to make OpenGL programming easy. You can download Basic4GL for free from: http://www.basic4gl.net.

We'll be learning by example, so I encourage you to keep Basic4GL open and be ready to cut and paste or type in a program to see what it does.
The best way to learn is to experiment, so feel free to change the code and see what happens. Basic4GL is designed to be a safe programming environment, so don't worry, you won't break anything. The worst that should ever happen is that the program will stop and say that there's an error.

DISCLAIMER: While every effort has been made to make Basic4GL a safe programming language, computers are complex mechanisms, and it is almost impossible to claim anything with 100% certainty. Therefore I (Tom Mulgrew, the author of Basic4GL) cannot and do not take any responsibility for anything that Basic4GL may or may not do to you, your computer or anything else. The software is strictly to be used at your own risk.

What is OpenGL?

So what exactly is OpenGL? And how does it relate to 3D computer graphics?

OpenGL was created by Silicon Graphics (SGI) as an Application Programming Interface (API) specification. It tells you what lines of code need to go into a program in order to draw 3D graphics images.
For example, it says that the following program:

glBegin (GL_TRIANGLES)
 glColor3f (1, 0, 0): glVertex3f ( 0, 1, -2)
 glColor3f (0, 1, 0): glVertex3f (-1,-1, -2)
 glColor3f (0, 0, 1): glVertex3f ( 1,-1, -2)
glEnd ()
SwapBuffers ()

Will draw a coloured triangle.

This is the first example program by the way. You can type it into the main program window of Basic4GL, or just cut and paste it. The run it by pressing the green "Go" button on the toolbar.

Try it.

If all goes to plan, you should now be looking at something like the triangle pictured.

If you've typed in the example and clicked the "Go" button, and you don't see a triangle like the picture, then there's a problem somewhere, and we'll have to figure out what it is.
Try the following:
  1. First, check over your program for any obvious mistakes.
    If the cursor has jumped to the middle of the program, then look around the cursor to see if you can identify the problem. Also look at the status bar (along the bottom of the text editor window) for a description of why the program stopped, or wouldn't run.
  2. If step one doesn't work, try opening one of the example programs that came with Basic4GL.
    Click the open button on the toolbar (with a picture of a folder opening on it). Then double click the "programs" folder. The Basic4GL example programs are stored in the "programs" folder. Choose one (for example "camera.gb"), and run it with the "Go" button.
    If it appears to run, then you know that Basic4GL can run on your computer.
    Otherwise you will need to figure out what's wrong and fix it - that's about as much advice as I can give you, from this point you're on your own

It's important to note that OpenGL is a specification. It says what the computer and graphics system should do when OpenGL commands run, but it doesn't necessarily say how, nor does it have to supply any program code to drive it. Instead this task generally falls to the 3D graphics card makers, who release OpenGL drivers which implement the OpenGL specification for their particular graphics card (or range of graphics cards).

Without an accepted graphics library specification like OpenGL, you would have to write different code for every type of 3D graphics card that you want your program to run on, an impractical amount of work.

So what can OpenGL do?

OpenGL does realistic modern 3D computer graphics, with texturemapping, lighting and all the bells and whistles.
It also uses modern 3D graphics hardware, which means it does 3D graphics fast!
OpenGL has been used for 3D modelling programs like CAD, 3D visualisation / virtual reality, 3D demos, and perhaps most importantly, 3D games.


3D theory - Vectors, axes and dimensions

The triangle example was certainly big and colourful, but we didn't really say anything about how it works.

To explain we would have to talk about coordinate systems, vectors and projection. But we can't do that until we've explained what each of these are, and to do that, we need to start with some basic 3D graphics theory.

With 3D graphics, the idea is to make it look like there is something behind the computer screen.
That something can be as simple as a small shape, or as complex as a moving realistic 3D object, (say a car, a dragon or a samurai warrior).
We try to draw an image on the computer screen that makes it look as if the screen was a window into that world.

So as a starting point we need to store our imaginary world in the computer in a format that it can work with.

Enter the "vertex".


Joining the dots

Here's a program to draw a 3D wireframe cube. It's a little bit long winded (we will learn some better ways to do this later), so you might want to cut and paste it into Basic4GL.

dim vertex#(8)(2)
vertex#(1) = vec3 (-1, 1, -5)
vertex#(2) = vec3 (-1,-1, -5)
vertex#(3) = vec3 ( 1,-1, -5)
vertex#(4) = vec3 ( 1, 1, -5)
vertex#(5) = vec3 (-1, 1, -7)
vertex#(6) = vec3 (-1,-1, -7)
vertex#(7) = vec3 ( 1,-1, -7)
vertex#(8) = vec3 ( 1, 1, -7)

glBegin (GL_LINE_LOOP)
    glVertex3fv (vertex#(1))
    glVertex3fv (vertex#(2))
    glVertex3fv (vertex#(3))
    glVertex3fv (vertex#(4))
glEnd ()
glBegin (GL_LINE_LOOP)
    glVertex3fv (vertex#(5))
    glVertex3fv (vertex#(6))
    glVertex3fv (vertex#(7))
    glVertex3fv (vertex#(8))
glEnd ()
glBegin (GL_LINES)
    glVertex3fv (vertex#(1))
    glVertex3fv (vertex#(5))
    glVertex3fv (vertex#(2))
    glVertex3fv (vertex#(6))
    glVertex3fv (vertex#(3))
    glVertex3fv (vertex#(7))
    glVertex3fv (vertex#(4))
    glVertex3fv (vertex#(8))
glEnd ()      
SwapBuffers ()

All 3D graphics starts with vertices. These are points in 3D space that are used to specify the corner "dots" of the 3D object, that we can join together to make the 3D image. We store each vertex as a 3D vector.
Note: Vector and vertex are often used interchangeably.
A vector is a point in 3D space. It has a very general meaning.
A vertex is a specialised type of vector. It is a point in 3D space that corresponds to the corner of a 3D object.

A vector is stored as 3 numbers.
The first number we call the "X coordinate", the second we call the "Y coordinate" and the third the "Z coordinate".
Each coordinate corresponds to a direction.
In OpenGL the directions are as follows:

Each number tells us how many units to go in that corresponding direction starting from the start position. (If the number is negative, it means we go that many units in the opposite direction).
So if we take the first vector (-1, 1, -5) we can see that it is:

relative to the starting position. The starting position is called the origin, and it corresponds to the viewpoint, (in otherwords; your eyeball).

In our example, the vertices are the corners of our cube, and we tell OpenGL to join them up with lines.

Note: "Vertex" and "Vector" have very similar meanings. A vertex denotes a point on a 3D model, presumably intended for drawing. A vector is a more general purpose.
A vertex is also a vector. A vector
can be a vertex, but it doesn't have to.

Drawing in OpenGL

Now that we've touched on what vertices are we can start to understand the OpenGL code.
Let's have a look at it from the start:

dim vertex#(8)(2)
vertex#(1) = vec3 (-1, 1, -5)
vertex#(2) = vec3 (-1,-1, -5)
vertex#(3) = vec3 ( 1,-1, -5)
vertex#(4) = vec3 ( 1, 1, -5)
vertex#(5) = vec3 (-1, 1, -7)
vertex#(6) = vec3 (-1,-1, -7)
vertex#(7) = vec3 ( 1,-1, -7)
vertex#(8) = vec3 ( 1, 1, -7)

We are creating 8 3D vertices (remember the "(2)" part actually allocates 3 values, index 0, 1, and 2), and setting them up as the corners of a cube. The cube is centred 6 units into the screen.

glBegin (GL_LINE_LOOP)

This is the first OpenGL command. Note that all OpenGL commands start with "gl", so they're easy to spot.
glBegin() tells OpenGL that we are about to send it some vertices, and it tells OpenGL what we want to do with them.
In this case we've used GL_LINE_LOOP which means we want it to join all the vertices together with lines, then join the last vertex to the first vertex to create a loop.

glVertex3fv (vertex#(1))
glVertex3fv (vertex#(2))
glVertex3fv (vertex#(3))
glVertex3fv (vertex#(4))

As you've probably guessed, this specifies the vertices.
glVertex3fv is one of a family of commands all starting with glVertex.
The "3fv" at the end tells us that this version:

3 Expects 3 coordinates
f These coordinates are in "float" format. Basic4GL uses "float" format internally for floating point numbers, so it makes the most sense to pass them in this way.
v Vertex will be passed in as an array. Otherwise we would have to pass in the X, Y and Z coordinates separately. (Like we did for the coloured triangle example.)

The next line:

glEnd ()

tells OpenGL that we have finished sending through this set of vertices, and it can now go off and draw them. This part draws a square, i.e the front part of the cube.

The next glBegin() - glEnd() block is much the same. It draws another square, representing the back of the cube.

The last block starts with glBegin (GL_LINES). GL_LINES tells OpenGL to join up each pair of vertices with a line. So vertex 1 gets joined to vertex 2, and vertex 3 to vertex 4 e.t.c. We use this to draw the lines that join the front square to the back square, completing the cube.

The last line in the program is:

SwapBuffers ()

Up until this point, OpenGL has been doing all it's drawing in the "Back buffer". This is an off-screen region of memory - you can't see it - where OpenGL does all it's drawing until the image is completed and ready to be displayed. SwapBuffers() transfers the image in the back buffer into the "Front buffer", which is OpenGL's name for the part of the screen where the image is displayed.

This system is called "double buffering", and is useful for creating flicker free animations, because it prevents you from seeing half drawn images.

From basic cubes to realistic scenes

Okay, that cube was pretty boring, and looked like something from the 1980's. But the principles involved are the same as those that drive modern graphics engines today. It just has a few extra drawing technologies built on top.

To illustrate:

If we start with vertices and lines.

To add more detail, just add more vertices and lines.

Replace the lines with textured polygons, to make it look solid.

Then add lighting.
We have ourselves a faily convincing 3D scene.

We'll be covering texturemapping and lighting later on, but for now the important thing to realise is that vertices are the backbone of 3D graphics.

Go to page << 1 2 >>