5. OpenGL Color (Version 2.0)

Introduction

A world without colour is a very dull world indeed. Colour makes up absolutely everything you see and without it, everything would either be a shade of grey, or just black. Luckily for us, this most fundamental component in any art form is standard in every graphics library, and even luckier for us, is the initial simplicity involved in setting and changing colours in OpenGL.

Colour Models

First we’ll have a look at some different colour models. There are many ways to describe colour in computer graphics. You may have a CMYK printer for example, which stores colours according to their Cyan, Magenta, Yellow and Key (black) values, or you may have a printer with an RGB cartridge, which takes Red, Green and Blue values, often with a separate cartridge for black. Then there are other formats such as HSL and HSV which stand for Hue, Saturation and Luminance or Value. You may have noticed the ability in some image editors to set the Hue and Saturation values, and they may refer to Luminance and Value as the Brightness.  Then there is YUV which is often used for cameras, and it is harder to describe. The Y value determines how bright the colour is, while the U and V values determine the colour. YUV is used because it uses less storage and therefore less bandwidth in cameras.

Coding

For most of us, we find it easiest to interpret colours in their RGB format, and OpenGL also works using this method. Now you may have used an image editor, where your RGB colours will range from 0 to 255. OpenGL works using colour values from 0 to 1, but you can interchange between both by either multiplying your OpenGL colour by 255, or dividing your other colour method by 255.

To give an example to get the following colours, you need the corresponding RGB values:

Red – (Red – 1.0f, Green – 0.0f, Blue – 0.0f)

Green – (Red – 0.0f, Green – 1.0f, Blue – 0.0f)

Blue – (Red – 0.0f, Green – 0.0f, Blue – 1.0f)

White – (Red – 1.0f, Green – 1.0f, Blue – 1.0f)

Black – (Red – 0.0f, Green – 0.0f, Blue – 0.0f)

Yellow – (Red – 1.0f, Green – 1.0f, Blue – 0.0f)

Pink (Magenta) – (Red – 1.0f, Green – 0.0f, Blue – 1.0f)

OpenGL provides us with several methods for setting the colours of shapes. There are methods that take 3 inputs, each one corresponding to Red, Green or Blue, and there are other methods that take 4 inputs, which relate to the Red, Green, Blue and Alpha values for our colours.

Now in order for you to set a colour, you can call one of these methods, with something similar to:

glColor3f(r, g, b);

Where the 3 stands for 3 colours, red, green and blue, and the f stands for a float, and tells OpenGL we are wanting to use float values to represent our colours. OpenGL also provides methods for using doubles, integers, bytes and shorts.

You will only ever want to use the Alpha value if you have some sort of blending enabled in your application, but once you have blending setup, setting colours with alpha values is as simple as:

glColor4f(r, g, b, a);

Keep in mind that the alpha value also ranges from 0.0 to 1.0, with 0.0 being completely transparent or see-through and 1.0 being completely opaque or filled.

In OpenGL fashion, there are also versions of these methods that can take arrays of values. But I won’t look into them.

Now if you remember that OpenGL is based on state machines, when you set a colour, you are setting the colour of everything that you draw since you made the call to glColor. Keep this in mind if you choose to draw something first, and then find that all your shapes are now this colour. You will have to set the colour of each shape separately.

As for when you set the colour of the shape, you have two options. You can either set the entire colour of the shape by calling glColor3f before you call glBegin, like so:

glColor3f(0.0f, 0.0f, 1.0f); // Colour our shape blue

glBegin(GL_QUADS); // Start drawing a quad
… // Vertex information
glEnd(); // Finish drawing our quad

Or you can set the colour of you shape on a per-vertex basis. This means you could set one vertex to red, another to green, another to blue and a fourth one to white, and have them all interpolate over the entire shape like so:

glBegin(GL_QUADS); // Start drawing a quad
glColor3f(1.0f, 0.0f, 0.0f); // Colour our shape blue
… // Vertex information
glColor3f(0.0f, 1.0f, 0.0f); // Colour our shape blue
… // Vertex information
glColor3f(0.0f, 0.0f, 1.0f); // Colour our shape blue
… // Vertex information
glColor3f(1.0f, 1.0f, 1.0f); // Colour our shape blue
… // Vertex information
glEnd(); // Finish drawing our quad

That is basically all there is to it, but I feel compelled to share the following information. If you happen to enable lighting in your OpenGL application and expect to find your colours still work, then by default you will be a little disappointed. However there is a fix for this and it is actually an OpenGL state that you can enable, called GL_COLOR_MATERIAL which sets your shapes material information to be that of the colour you assigned to it. You can enable this when you initialize your OpenGL state with:

glEnable(GL_COLOR_MATERIAL);

If you have any questions, please email 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 renderPrimitive (void) {
glColor3f(0.0f, 0.0f, 1.0f); // Set the colour of the square to blue

glBegin(GL_QUADS); // Start drawing a quad primitive
glVertex3f(-1.0f, -1.0f, 0.0f); // The bottom left corner
glVertex3f(-1.0f, 1.0f, 0.0f); // The top left corner
glVertex3f(1.0f, 1.0f, 0.0f); // The top right corner
glVertex3f(1.0f, -1.0f, 0.0f); // The bottom right corner
glEnd();
}

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

renderPrimitive(); // 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
  • 15