6. OpenGL Cube (Version 2.0)

Introduction

All is perfectly fine if we want to draw standard 2D shapes in OpenGL, but the next step up is 3D shapes, and it is these shapes that will really make your application look impressive. The best part about 3D shapes, is that they are made up of 2D shapes, just drawn in 3D space. While OpenGL provides methods for easily rendering 2D shapes, it doesn’t provide any methods for shapes such as cubes, spheres, pyramids, etc. But all is not lost, you have two choices. The first choice is to create the shapes yourself, work out the vertices, determine which vertices you want to use to make faces, and hand code it all in. The next choice, not including 3D modeling applications and model loaders, is to use GLUT for simple 3D shapes. GLUT comes with the ability to render some extremely basic 3D shapes such as a cube, sphere (without texture coordinates), cone, torus/donut and the all famous teapot. GLUT also lets us render this in both their wireframe version, or their regular filled version. GLUT also comes with several other shapes, but they are not all that common. Lets take a look at the code required to render these more common shapes:

Cube

glutWireCube(double size);
glutSolidCube(double size);

This will create a cube with the same width, height and depth/length, each the length of the size parameter specified. This cube in GLUT also comes with surface normals but not texture coordinates.

Sphere

glutWireSphere(double radius, int slices, int stacks);
glutSolidSphere(double radius, int slices, int stacks);

The calls to create a sphere in GLUT require you to give a radius, which determines the size of the sphere, and the number of stacks and slices. The stacks and slices determine the quality of the sphere, and are the number of divisions in vertical and horizontal directions. The sphere does come with surface normals, but does not come with texture coordinates.

Cone

glutWireCone(double radius, double height, int slices, int stacks);
glutSolidCone(double radius, double height, int slices, int stacks);

If you want to create a cone, you would use the above GLUT calls. These calls are almost identical to that of the sphere code, we have a radius and the stacks and slices. But it also takes another parameter which defines the height of the cone. Also note that the radius of the cone, refers to the radius of the base of the cone. The cone will come with surface normals, but does not come with texture coordinates.

Torus

glutWireTorus(double inner_radius, double outer_radius, int sides, int rings);
glutSolidTorus(double inner_radius, double outer_radius, int sides, int rings);

A torus looks exactly like a donut. It has an inner radius, which specifies the size of the hole in the middle, an outer radius, which specifies the outer side of the torus from the centre (not the inner radius onwards), the sides specifies the number of sides in each radial section and finally, the rings specify how many radial divisions are used for the torus.

Teapot

glutWireTeapot(double size);
glutSolidTeapot(double size);

The all famous teapot was first created in 1975 by Martin Newell and is widely used for testing in computer graphics because it is round, has saddle points, can project a shadow onto itself and looks decent when it is untextured. All you have to do to create the teapot is specify the size for the teapot. The teapot comes with surface normals and texture coordinates which means it is perfect for testing bump mapping, environment mapping, and many other effects.

Code

As you can probably tell from the above calls to GLUT, these shapes are extremely easy to use in OpenGL. Find a section in your code and simply insert the call you want. So let’s remove our renderPrimitive method from the previous tutorial in our display method, we are going to replace the call to renderPrimitive with a call to create a cube.

void display (void) {
…

glTranslatef(0.0f, 0.0f, -5.0f); // Push eveything 5 units back into the scene, otherwise we won't see the primitive

glutWireCube(2.0f); // Render the primitive

glFlush(); // Flush the OpenGL buffers to the window
}

You should now have a nice 3D cube in your OpenGL application. If you have any questions, you can always contact me at swiftless@gmail.com

Tutorial Code

#include <GL/glew.h> // Include the GLEW header file

#include <GL/glut.h> // Include the GLUT header file

bool* keyStates = new bool[256]; // Create an array of boolean values of length 256 (0-255)

void keyOperations (void) {
if (keyStates['a']) { // If the 'a' key has been pressed
// Perform 'a' key operations
}
}

void display (void) {
keyOperations();

glClearColor(1.0f, 0.0f, 0.0f, 1.0f); // Clear the background of our window to red
glClear(GL_COLOR_BUFFER_BIT); //Clear the colour buffer (more buffers later on)
glLoadIdentity(); // Load the Identity Matrix to reset our drawing locations

glTranslatef(0.0f, 0.0f, -5.0f); // Push eveything 5 units back into the scene, otherwise we won't see the primitive

glutWireCube(2.0f); // Render the primitive

glFlush(); // Flush the OpenGL buffers to the window
}

void reshape (int width, int height) {
glViewport(0, 0, (GLsizei)width, (GLsizei)height); // Set our viewport to the size of our window
glMatrixMode(GL_PROJECTION); // Switch to the projection matrix so that we can manipulate how our scene is viewed
glLoadIdentity(); // Reset the projection matrix to the identity matrix so that we don't get any artifacts (cleaning up)
gluPerspective(60, (GLfloat)width / (GLfloat)height, 1.0, 100.0); // Set the Field of view angle (in degrees), the aspect ratio of our window, and the new and far planes
glMatrixMode(GL_MODELVIEW); // Switch back to the model view matrix, so that we can start drawing shapes correctly

}

void keyPressed (unsigned char key, int x, int y) {
keyStates[key] = true; // Set the state of the current key to pressed
}

void keyUp (unsigned char key, int x, int y) {
keyStates[key] = false; // Set the state of the current key to not pressed
}

int main (int argc, char **argv) {
glutInit(&argc, argv); // Initialize GLUT
glutInitDisplayMode (GLUT_SINGLE); // Set up a basic display buffer (only single buffered for now)
glutInitWindowSize (500, 500); // Set the width and height of the window
glutInitWindowPosition (100, 100); // Set the position of the window
glutCreateWindow ("Your first OpenGL Window"); // Set the title for the window

glutDisplayFunc(display); // Tell GLUT to use the method "display" for rendering

glutReshapeFunc(reshape); // Tell GLUT to use the method "reshape" for reshaping

glutKeyboardFunc(keyPressed); // Tell GLUT to use the method "keyPressed" for key presses
glutKeyboardUpFunc(keyUp); // Tell GLUT to use the method "keyUp" for key up events

glutMainLoop(); // Enter GLUT's main loop
}
  • March 25, 2010
  • 17