Featured Posts

8. Bump Mapping in GLSL8. Bump Mapping in GLSL Introduction Bump mapping is essential in todays computer games, and computer graphics in general. Would you like to know the best thing about it? It is extremely simple to implement. Bump mapping works...

Read more

Swiftless GLSL Shader DeveloperSwiftless GLSL Shader Developer Swiftless GLSL Shader Developer   Version 0.1a Currently Swiftless GLSL Shader Developer is in it's first public release, and is currently in alpha status, meaning it is not complete and may contain...

Read more

Wordpress Optimization Wordpress Website Optimizations Introduction Wordpress itself is a fairly wonderful tool. Since switching to it, I find it is a lot quicker to make changes to my website and it is also quicker to get...

Read more

36. OpenGL Framebuffers36. OpenGL Framebuffers Introduction Frame buffers are one of those mythical things that we have all heard of, but many beginner OpenGL developers avoid because there is not much information about them, and they can be confusing...

Read more

1. Terrain Class1. Terrain Class Terrain is one of those things that so far, hasn't been perfectly recreated in computer graphics. But it is almost there! Looking over a beautiful landscape can be one of the most amazing feelings in the...

Read more

  • Prev
  • Next

36. OpenGL Framebuffers

Posted on : 22-04-2010 | By : Swiftless | In : OpenGL

Tags: , , , , , , , , ,

2

Introduction

Frame buffers are one of those mythical things that we have all heard of, but many beginner OpenGL developers avoid because there is not much information about them, and they can be confusing at first. A frame buffer can be thought of as another window that we render to, but we don’t end up seeing.

Now you might be thinking, if we draw something, but we don’t end up seeing it, then what is the point? Have you ever heard of off-screen rendering? I might ask you this instead, have you ever seen a reflection in a game of a live scene? Well, to get this reflection, we typically have to render the scene from the angle of the reflection first, and then we turn that render into a texture and bind it to whatever shape has the reflection attached to it. This initial rendering of the reflection is typically done in a frame buffer for speed, as we can bind a frame buffer straight to a texture.

If you have ever heard of pixel buffers, don’t get them confused with frame buffers, they are different, but can be used together. I won’t go into pixel buffers here, I might write a tutorial on them later on, but they are highly useful for asynchronous texture reads and writes. I once had a project, and part of it required I write to two frame buffers and read back the data, and then perform operations on this data and push it back to the GPU as a texture as quickly as possible. Using a combination of frame buffers and pixel buffers, I went from approximately 5 frames per second doing this, to 30 frames per second, and if the demand arises, I will post a tutorial on how to do this. It was a case where offloading the information to the GPU was not possible.

You should now have an idea of what frame buffers are, in short, they are a rendering context that can be bound to a texture, so let’s start coding them and see what we come up with. I am going to aim for a quad, with a texture of a rotating cube on it. It is a simple example, but highly useful, as you can imagine, the entire scene can be rendered into a frame buffer, and then placed onto a quad for some post processing.

Code

Frame buffer objects are stored like textures. OpenGL will store the information on the graphics card, and it will return an ID associated with that texture for us to place inside an unsigned integer. Also, as seen with textures, the frame buffer ID of 0 (zero) is reserved by OpenGL and is used to unbind the current frame buffer. Also, frame buffers can have several buffers attached. The default buffer is the colour buffer, but you can also bind depth buffers, stencil buffers, etc. So let’s create some variables to hold our frame buffer, frame buffers depth buffer and the texture we are going to store our frame buffer in.

unsigned int fbo; // The frame buffer object
unsigned int fbo_depth; // The depth buffer for the frame buffer object
unsigned int fbo_texture; // The texture object to write our frame buffer object to

After we have all the variables required to create and use our frame buffers (yes, we only need three variables), we are going to add some extra variables. First, we need two integer values for the width and height of our GLUT window, this is because when you create a frame buffer, you need to specify the width and the height of the texture, and when you use the frame buffer, you need to change the viewport size to match the texture size. Because frame buffers are independent of the size of the GLUT window, you can use them to create higher or lower resolution textures than your regular scene. Typically you would use a lower resolution texture for effects such as reflections so that it renders quicker. The last extra variable we are going to use will just hold how much our teapot in our frame buffer scene will rotate.

int window_width = 500; // The width of our window
int window_height = 500; // The height of our window

float rotation_degree = 0.0f; // The angle of rotation in degrees for our teapot

The next step we have to do is to create/initialize our frame buffer, the associated depth buffer, and the texture we are going to render to. Typically it is done in the following order:

  1. Create the Depth Buffer that we are going to use with our frame buffer.
  2. Create the Texture that we are going to bind our frame buffer to.
  3. Create the actual Frame Buffer.
  4. Bind the texture to the frame buffer.
  5. Bind the depth buffer to the frame buffer.
  6. Check for errors.

You can check for errors along the way if you wish, but I will just be using one check to make sure our final frame buffer is complete.

Frame Buffer – Depth Buffer

Let’s create the depth buffer we are going to use. To begin with, create a method call initFrameBufferDepthBuffer. This method is going to take no parameters and is not going to return anything. This method is going to contain all code related to the depth buffer we are going to use.

void initFrameBufferDepthBuffer(void) {

}

Inside of this method to create the depth buffer, the first call we need to make will create a render buffer for OpenGL to use, and is very similar to the code used to create textures.

glGenRenderbuffersEXT(1, &fbo_depth); // Generate one render buffer and store the ID in fbo_depth

This will create a render buffer, and store the ID in our fbo_depth variable for us to access.  Once the render buffer is created for the depth buffer, we then need to bind the buffer so that we can play with it and once we are finished with it, we need to bind the null render buffer, which takes the value of 0. When we are binding a frame buffer, it is once again very similar to texturing, so let’s place our binding code inside our method to fill between.

void initFrameBufferDepthBuffer(void) {
glGenRenderbuffersEXT(1, &fbo_depth); // Generate one render buffer and store the ID in fbo_depth
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo_depth); // Bind the fbo_depth render buffer
...
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); // Unbind the render buffer
}

Next, we need to fill in the … between the binding of the render buffers. These next two lines are the lines that tell OpenGL that this render buffer will be used for depth. The first line tells OpenGL that we are going to be storing the depth component, and we are going to monitor the entire size of the window. The next line then says that we are going to use fbo_depth to render the depth buffer/attachment.

glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, window_width, window_height); // Set the render buffer storage to be a depth component, with a width and height of the window

glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo_depth); // Set the render buffer of this buffer to the depth buffer

Frame Buffer – Texture

Recapping on what we have done, we have created a render buffer that will store the depth component of the buffer that it is attached to. Now we need to create the texture that we want to store our frame buffer in. To do this, let’s create another method similar to the one we just created, but I am going to call this one initFrameBufferTexture. Because we are only creating a texture here, I am not really going to explain this code, the code comments should outline what is going on if you don’t know about texturing in OpenGL (in which case, you are diving in fairly deep straight out).

void initFrameBufferTexture(void) {
glGenTextures(1, &fbo_texture); // Generate one texture

glBindTexture(GL_TEXTURE_2D, fbo_texture); // Bind the texture fbo_texture

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, window_width, window_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); // Create a standard texture with the width and height of our window

// Setup the basic texture parameters

glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

// Unbind the texture
glBindTexture(GL_TEXTURE_2D, 0);
}

Frame Buffer – Initialization

Finally, we need one more method; this one will be called initFrameBuffer and will make calls to the above methods we have created, as well as creating the frame buffer and attaching the texture and the depth buffer.

void initFrameBuffer(void) {
initFrameBufferDepthBuffer(); // Initialize our frame buffer depth buffer

initFrameBufferTexture(); // Initialize our frame buffer texture
…
}

After making the calls to our above methods, we need to create the frame buffer, and bind it. This is extremely similar to how we created the render buffer for the depth component, and how we create textures, so the following should look vaguely familiar.

glGenFramebuffersEXT(1, &fbo); // Generate one frame buffer and store the ID in fbo
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // Bind our frame buffer
…
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind our frame buffer

This code will generate one frame buffer, and then bind it so we can modify it, and then finally it will unbind it. This is fairly straight forward, and the next two calls will attach the texture and render buffer to our frame buffer. First off, let’s attach the texture to the frame buffer.

glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, fbo_texture, 0); // Attach the texture fbo_texture to the color buffer in our frame buffer

Now that we have a texture, theoretically we can use this straight out, but you won’t get any depth information. So we need to go ahead and attach the depth render buffer we created called fbo_depth, to our frame buffer.

glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo_depth); // Attach the depth buffer fbo_depth to our frame buffer

And now we have a frame buffer, which outputs to a texture and also has a depth buffer, which we can use. Well, we think we do, so first let’s check if our frame buffer is complete and there were no problems. To do this, we can make a call to glCheckFramebufferStatusEXT while our frame buffer is bound, and this will give us back a GLenum with the status of our frame buffer. For our frame buffer to be complete, we need to check that the status is equal to GL_FRAMEBUFFER_COMPLETE_EXT. We can do this with a simple if statement. Note that if you want the output to the console, you need to include <iostream> into your file.

GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); // Check that status of our generated frame buffer

if (status != GL_FRAMEBUFFER_COMPLETE_EXT) // If the frame buffer does not report back as complete
{
std::cout << "Couldn't create frame buffer" << std::endl; // Make sure you include <iostream>
exit(0); // Exit the application
}

General Initialization

Because in this example, we want to use the frame buffer constantly, I am going to create an init method which will call the initFrameBuffer method, and init will be called straight after we initialize GLEW, which is straight after we call glutCreateWindow. So here is our init method, which in this example, enables texturing, enables depth testing, and then initializes our frame buffer.

void init(void) {
glEnable(GL_TEXTURE_2D); // Enable texturing so we can bind our frame buffer texture
glEnable(GL_DEPTH_TEST); // Enable depth testing

initFrameBuffer(); // Create our frame buffer object
}

Next up, here is an example of my main method, which calls glewInit and calls our own init method.

int main (int argc, char **argv) {
…
glutCreateWindow ("You’re first OpenGL Window"); // Set the title for the window

if (GLEW_OK != glewInit()) {
std::cout << "Couldn't initialize GLEW" << std::endl;
exit(0);
}

init();
…
}

Frame Buffer – Usage

To use our frame buffer, I am first going to give you the display method, and whilst you could put all your code in here, I am going to make a call to a method to render our teapot scene. This display method builds upon the tutorial for creating a square.

So it looks something like the following code, which will create a square with texture coordinates, and I have placed it back 2 units so that it fills up most of the screen. Keep in mind, that I am not doing anything with the frame buffer at the moment; this is just a standard display method.

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 | GL_DEPTH_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, -2.0f);

glBegin(GL_QUADS);

glTexCoord2f(0.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f); // The bottom left corner

glTexCoord2f(0.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 0.0f); // The top left corner

glTexCoord2f(1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 0.0f); // The top right corner

glTexCoord2f(1.0f, 0.0f);
glVertex3f(1.0f, -1.0f, 0.0f); // The bottom right corner

glEnd();

glutSwapBuffers();
}

Now we will go ahead and bind our frame buffer texture to the quad. This is done just like binding a regular texture, because it is just a regular texture. The only difference between the texture we use for our frame buffer, and a standard texture we load in from a file, is that this texture is filled in on the GPU by OpenGL.

So right before your quad begins, bind your frame buffer texture, and then after you finish drawing your quad, unbind it.

glBindTexture(GL_TEXTURE_2D, fbo_texture);

glBegin(GL_QUADS);

…

glEnd();

glBindTexture(GL_TEXTURE_2D, 0);

You should be able to run this now, but unfortunately because we haven’t rendered anything into the frame buffer, nothing will appear on our quad, it will be as if we never bound a texture. So let’s create a method where we are going to render our frame buffer. I am going to call this renderTeapotScene, because I am using it to render a teapot.

void renderTeapotScene(void) {

}

renderTeapotScene is going to be called from inside our display method, right after our keyOperations and before we do any actual rendering.

void display(void) {
keyOperations();

renderTeapotScene();

...
}

Inside of our renderTeapotScene method, we need to first bind our frame buffer so that we can render to it, and then unbind it when we are finished rendering. I am also going to add in some extra code at the very end of this method, just to update the amount in which we are going to rotate our teapot.

void renderTeapotScene(void) {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // Bind our frame buffer for rendering

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind our texture

rotation_degree += 0.5f;
if (rotation_degree > 360.0f)
rotation_degree = 0.0f;
}

So far, everything should be fine, except when you bind a frame buffer, you need to set the size of the viewport that the frame buffer will render to. This is done with a call to glViewport, but first I am going to do some more management orientated activities, and store the current state of our GL_ENABLE_BIT and our GL_VIEWPORT_BIT. This is so that when we finish, we can put these back to how they were and not having any glEnable or glViewport calls modify our regular rendering. It is also wise to store information such as GL_LIGHTING_BIT if you are using lighting, and any other states you might need.

void renderTeapotScene(void) {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // Bind our frame buffer for rendering
glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT); // Push our glEnable and glViewport states

glPopAttrib(); // Restore our glEnable and glViewport states
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind our texture

rotation_degree += 0.5f;
if (rotation_degree > 360.0f)
rotation_degree = 0.0f;
}

It is our calls to glPushAttrib and glPopAttrib which will save and restore our states. The next step as I said is to set the viewport size for rendering, and then I am going to clear the colour buffer, depth buffer and reset the model view matrix, just like you would in your regular display method.

void renderTeapotScene(void) {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // Bind our frame buffer for rendering
glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT); // Push our glEnable and glViewport states
glViewport(0, 0, window_width, window_height); // Set the size of the frame buffer view port

glClearColor (0.0f, 0.0f, 1.0f, 1.0f); // Set the clear colour
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear the depth and colour buffers

glLoadIdentity();  // Reset the modelview matrix

glPopAttrib(); // Restore our glEnable and glViewport states
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind our texture

rotation_degree += 0.5f;
if (rotation_degree > 360.0f)
rotation_degree = 0.0f;
}

This should be starting to look a little familiar inside of our frame buffer and push attributes calls, and you are probably right, everything you do from now on is just like rendering a normal scene, only you don’t need to call glFlush or glutSwapBuffers like you would with a regular render as we are not pushing the output to the screen. So now all we need to do is add the code in for our teapot rendering. I am going to translate it back five units, and then rotate it along the x and the y axis.

void renderTeapotScene(void) {
…
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear the depth and colour buffers
glLoadIdentity();  // Reset the modelview matrix

glTranslatef(0.0f, 0.0f, -5.0f); // Translate back 5 units

glRotatef(rotation_degree, 1.0f, 1.0f, 0.0f); // Rotate according to our rotation_degree value

glutSolidTeapot(1.0f); // Render a teapot

glPopAttrib(); // Restore our glEnable and glViewport states
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind our texture
…
}

If you followed everything as I have said correctly, then you should be able to compile this and run it. You should then see a quad with a red background, with a texture of a spinning teapot with a blue background attached to the quad.

Well done if you managed that, and now have your head around frame buffers!

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
#include <iostream> // Allow us to print to the console

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

unsigned int fbo; // The frame buffer object
unsigned int fbo_depth; // The depth buffer for the frame buffer object
unsigned int fbo_texture; // The texture object to write our frame buffer object to

int window_width = 500; // The width of our window
int window_height = 500; // The height of our window

float rotation_degree = 0.0f; // The angle of rotation in degrees for our teapot

void initFrameBufferDepthBuffer(void) {

glGenRenderbuffersEXT(1, &fbo_depth); // Generate one render buffer and store the ID in fbo_depth
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo_depth); // Bind the fbo_depth render buffer

glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, window_width, window_height); // Set the render buffer storage to be a depth component, with a width and height of the window

glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo_depth); // Set the render buffer of this buffer to the depth buffer

glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); // Unbind the render buffer
}

void initFrameBufferTexture(void) {
glGenTextures(1, &fbo_texture); // Generate one texture
glBindTexture(GL_TEXTURE_2D, fbo_texture); // Bind the texture fbo_texture

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, window_width, window_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); // Create a standard texture with the width and height of our window

// Setup the basic texture parameters
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

// Unbind the texture
glBindTexture(GL_TEXTURE_2D, 0);
}

void initFrameBuffer(void) {
initFrameBufferDepthBuffer(); // Initialize our frame buffer depth buffer

initFrameBufferTexture(); // Initialize our frame buffer texture

glGenFramebuffersEXT(1, &fbo); // Generate one frame buffer and store the ID in fbo
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // Bind our frame buffer

glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, fbo_texture, 0); // Attach the texture fbo_texture to the color buffer in our frame buffer

glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo_depth); // Attach the depth buffer fbo_depth to our frame buffer

GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); // Check that status of our generated frame buffer

if (status != GL_FRAMEBUFFER_COMPLETE_EXT) // If the frame buffer does not report back as complete
{
std::cout << "Couldn't create frame buffer" << std::endl; // Output an error to the console
exit(0); // Exit the application
}

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind our frame buffer
}

void init(void) {
glEnable(GL_TEXTURE_2D); // Enable texturing so we can bind our frame buffer texture
glEnable(GL_DEPTH_TEST); // Enable depth testing

initFrameBuffer(); // Create our frame buffer object
}

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

void renderTeapotScene(void) {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // Bind our frame buffer for rendering
glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT); // Push our glEnable and glViewport states
glViewport(0, 0, window_width, window_height); // Set the size of the frame buffer view port

glClearColor (0.0f, 0.0f, 1.0f, 1.0f); // Set the clear colour
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear the depth and colour buffers
glLoadIdentity();  // Reset the modelview matrix

glTranslatef(0.0f, 0.0f, -5.0f); // Translate back 5 units

glRotatef(rotation_degree, 1.0f, 1.0f, 0.0f); // Rotate according to our rotation_degree value

glutSolidTeapot(1.0f); // Render a teapot

glPopAttrib(); // Restore our glEnable and glViewport states
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind our texture

rotation_degree += 0.5f;
if (rotation_degree > 360.0f)
rotation_degree = 0.0f;
}

void display (void) {
keyOperations(); // Perform any key presses

renderTeapotScene(); // Render our teapot scene into our frame buffer

glClearColor(1.0f, 0.0f, 0.0f, 1.0f); // Clear the background of our window to red
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_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, -2.0f);

glBindTexture(GL_TEXTURE_2D, fbo_texture); // Bind our frame buffer texture

glBegin(GL_QUADS);

glTexCoord2f(0.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f); // The bottom left corner

glTexCoord2f(0.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 0.0f); // The top left corner

glTexCoord2f(1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 0.0f); // The top right corner

glTexCoord2f(1.0f, 0.0f);
glVertex3f(1.0f, -1.0f, 0.0f); // The bottom right corner

glEnd();

glBindTexture(GL_TEXTURE_2D, 0); // Unbind any textures

glutSwapBuffers();
}

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_DOUBLE | GLUT_DEPTH | GLUT_RGBA); // 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 ("You’re first OpenGL Window"); // Set the title for the window

if (GLEW_OK != glewInit()) {
std::cout << "Couldn't initialize GLEW" << std::endl;
exit(0);
}

init();

glutDisplayFunc(display); // Tell GLUT to use the method "display" for rendering
glutIdleFunc(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
}
VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 9.0/10 (11 votes cast)
VN:F [1.9.3_1094]
Rating: +6 (from 6 votes)

10. OpenGL Scaling

Posted on : 25-03-2010 | By : Swiftless | In : OpenGL

Tags: , , , , ,

4

If you have worked with vectors before, you will know already that
scaling is simply stretching an object a certain amount.

Say we have an object, but we want it twice the height, we will
have to scale (stretch) it to twice the current height, along the y axis.

I am using:
glScalef(2, 0.5, 1);
in my display function.

If you look at the scale function on its own it takes:
The amount you want to stretch it on the:
x axis
y axis
z axis
In that order.

So I am stretching my cube, 2 times along the x axis, 0.5 times along the
y axis, and 1 time on the z axis.

So it will come out, twice as long, half as high, and the same depth.

And that is all there is to scaling, it is one of the very basic commands
in OpenGL.

If there are any problems with this code, please email me at swiftless@gmail.com

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
  #include <GL/gl.h>
#include <GL/glut.h>

GLfloat angle = 0.0;

void cube (void) {
    //scaled
    glScalef( 2.0, 0.5, 1.0 );  //twice as wide, half the height, 
same depth

    glRotatef(angle, 1.0, 0.0, 0.0);
    glRotatef(angle, 0.0, 1.0, 0.0);
    glRotatef(angle, 0.0, 0.0, 1.0);
    glColor4f(1.0, 0.0, 0.0, 0.25); //25% visible
    glutWireCube(2);
    //non scaled
    glRotatef(angle, 1.0, 0.0, 0.0);
    glRotatef(angle, 0.0, 1.0, 0.0);
    glRotatef(angle, 0.0, 0.0, 1.0);
    glColor4f(0.0, 1.0, 0.0, 0.25); //25% visible
    glutSolidCube(1);
}

void display (void) {
    glClearColor (0.0,0.0,0.0,1.0);
    glClear (GL_COLOR_BUFFER_BIT);
    glEnable(GL_BLEND); //enable the blending
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); /
/ set the blending

    glLoadIdentity();  
    gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    cube();
    glutSwapBuffers();
    angle ++;
}

void reshape (int w, int h) {
    glViewport (0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
    gluPerspective (60, (GLfloat)w / (GLfloat)h, 1.0, 100.0)
;
    glMatrixMode (GL_MODELVIEW);
}

int main (int argc, char **argv) {
    glutInit (&argc, argv);
    glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA); //set up 
for the alpha channel

    glutInitWindowSize (500, 500);
    glutInitWindowPosition (100, 100);
    glutCreateWindow (“A basic OpenGL Window);
    glutDisplayFunc (display);
    glutIdleFunc (display);
    glutReshapeFunc (reshape);
    glutMainLoop ();
    return 0;
}

VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 8.0/10 (4 votes cast)
VN:F [1.9.3_1094]
Rating: +1 (from 1 vote)

9. OpenGL Blending

Posted on : 25-03-2010 | By : Swiftless | In : OpenGL

Tags: , , , , ,

0

Blending consists of taking your normal RGB values and adding what is called A
for Alpha. Our RGB function becomes RGBA where the Alpha value monitors
the opacity of transparency of the current colour.

Now to get this option into our OpenGL application we need to add the A value
to our window. To do this just change the line:
glutInitDisplayMode (GLUT_DOUBLE);
to include “| GLUT_RGBA)” somewhere on the end.

Now that our window supports Alpha values we want to be able to use the
blending function built into OpenGL. To do this we enable the blending
just like any other option with:
glEnable(GL_BLEND);

So we now have blending enabled. But how do we use it?
We need to set up how the current objects are going to be blended.
I am using the blending function:
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Which takes the current colour, and blends it with the colours behind it
according to the Alpha value we set.

Now to set the Alpha value we need to change our current colour line which
looks like: glColor3f(1, 0, 0);
to make it look like:
glColor4f(1, 0, 0, 0.2);
Here the fourth value of 0.2 is our opacity level. With 1 being the highest
(fully opaque), and 0 being the lowest (fully transparent, will not be visible).

And that is all that there is.

Just remember that objects that are drawn on the
screen are drawn in the order in which you choose to draw them. So if you
draw a square (square1), before another square (square2), then if square1
is brought infront of square2 while square1 has an alpha value, then
square1 will not show square2 behind it.

If you have any queries feel free to email me at swiftless@gmail.com

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
  #include <GL/gl.h>
#include <GL/glut.h>

GLfloat angle = 0.0;

void cube (void) {
    glRotatef(angle, 1.0, 0.0, 0.0);
    glRotatef(angle, 0.0, 1.0, 0.0);
    glRotatef(angle, 0.0, 0.0, 1.0);
    glColor4f(1.0, 0.0, 0.0, 0.2); //set the color and alpha of 
the cube

    glutSolidCube(2);
    glColor4f(0.0, 1.0, 0.0, 0.5); //set the color and alpha of 
the cube

    glutSolidCube(1);
}

void display (void) {
    glClearColor (0.0,0.0,0.0,1.0);
    glClear (GL_COLOR_BUFFER_BIT);
    glEnable(GL_BLEND); //enable the blending
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); /
/set the blend function

    glLoadIdentity();  
    gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    cube();
    glutSwapBuffers();
    angle ++;
}

void reshape (int w, int h) {
    glViewport (0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
    gluPerspective (60, (GLfloat)w / (GLfloat)h, 1.0, 100.0)
;
    glMatrixMode (GL_MODELVIEW);
}

int main (int argc, char **argv) {
    glutInit (&argc, argv);
    glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA); //set the
 alpha buffer

    glutInitWindowSize (500, 500);
    glutInitWindowPosition (100, 100);
    glutCreateWindow (“A basic OpenGL Window);
    glutDisplayFunc (display);
    glutIdleFunc (display);
    glutReshapeFunc (reshape);
    glutMainLoop ();
    return 0;
}

VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 9.0/10 (5 votes cast)
VN:F [1.9.3_1094]
Rating: +1 (from 1 vote)

8. OpenGL Double Buffering

Posted on : 25-03-2010 | By : Swiftless | In : OpenGL

Tags: , , , , ,

3

Last time we looked at rotation the cube looked ‘broken’ now it
looked like this because we had a single buffer running. This
means that the program is automatically drawing straight to the
window. To fix this we add a second buffer, by changing the:
glutInitDisplayMode (GLUT_SINGLE);
to:
glutInitDisplayMode (GLUT_DOUBLE);
this is giving the programa buffer to draw what it has to, then transfer
what is acctually needed to the screen.
You may notice that alot of games these days even have a triple
buffer, this is pretty redundant in OpenGL, in fact it doesn’t even exist in OpenGL.

When changing the buffer from Single to Double we also have to
tell the program to swap the buffers, so we acctually see what
is on the second, and not just what we saw before.

To do this, change the line in the ‘display’ function that says:
glFlush();
to:
glutSwapBuffers();

And your done, the cube should be rotating perfectly.

If you have any questions, please email me at swiftless@gmail.com

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
  #include <GL/gl.h>
#include <GL/glut.h>

GLfloat angle = 0.0; //set the angle of rotation

void cube (void) {
    glRotatef(angle, 1.0, 0.0, 0.0); //rotate on the x axis
    glRotatef(angle, 0.0, 1.0, 0.0); //rotate on the y axis
    glRotatef(angle, 0.0, 0.0, 1.0); //rotate on the z axis
    glColor3f(1.0, 0.0, 0.0);
    glutWireCube(2);
}

void display (void) {
    glClearColor (0.0,0.0,0.0,1.0);
    glClear (GL_COLOR_BUFFER_BIT);
    glLoadIdentity();  
    gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    cube();
    glutSwapBuffers();
    angle ++;
}

void reshape (int w, int h) {
    glViewport (0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
    gluPerspective (60, (GLfloat)w / (GLfloat)h, 1.0, 100.0)
;
    glMatrixMode (GL_MODELVIEW);
}

int main (int argc, char **argv) {
    glutInit (&argc, argv);
    glutInitDisplayMode (GLUT_DOUBLE); //set up the double 
buffering

    glutInitWindowSize (500, 500);
    glutInitWindowPosition (100, 100);
    glutCreateWindow (“A basic OpenGL Window);
    glutDisplayFunc (display);
    glutIdleFunc (display);
    glutReshapeFunc (reshape);
    glutMainLoop ();
    return 0;
}

VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 9.7/10 (14 votes cast)
VN:F [1.9.3_1094]
Rating: +8 (from 8 votes)

7. OpenGL Rotation and Translation (Version 2.0)

Posted on : 25-03-2010 | By : Swiftless | In : OpenGL

Tags: , , , ,

10

Introduction

Placing an object into your scene, in a 3D OpenGL environment can often be quite the achievement when you have everything in place. But just placing an object in your scene can be a little boring, so to get some character movement, or object interaction, it is necessary to both translate and rotate objects, which OpenGL makes quite simple for us to do.

Behind the extremely simple OpenGL calls that we are going to use, lays some pretty intense mathematics which I am not going to go into during these tutorials. In short, it all revolves around matrices and there is a matrix known as a transformation matrix. By multiplying together different transformation matrices, you get your final transformation. Now don’t get transformation confused with translation though, a translation moves the position of an object while a transformation is a combination of translate and rotate.

Rotation

What is rotation? May be something you are asking yourself if you are totally new to computer graphics, or even new to maths. It’s a little hard to describe without a picture or even an animation, but picture an object sitting still, not moving at all. And then it turns on the spot. This turning on the spot is called rotation, and is measured by the number of degrees (or radians) you have turned from your starting position along any three axis in a 3D scene. With the three main axis being the X, Y and Z axis.

Translation

Now that you know what rotation is, comes the question as to what exactly is translation? Translation is movement along any of the three axis in a 3D scene, for example, moving something the left is a translation on the X axis if you are looking straight on. In OpenGL, the length of translation is called units, and a unit has no definitive length, which can be confusing, but bear with me. On OpenGL.org, the question as to what the length of a unit is has been asked, and the official response is “Whatever you want it to be”. Depending on your implementation of your scene, a unit can be a centimetre, metre or a kilometre (or if you work in Imperial measurements, inches, yards and miles), it’s entirely up to you. Unfortunately this does have its downside, if you ever find yourself having to merge several OpenGL applications, they may be using different measurement systems, and you may find things are the wrong size. Trust me, it can be a pain and there are times when I wish there was an unofficial standard. Personally I tend to use 1 unit is equal to 1 metre. In OpenGL, movements either up, left or towards the camera are negative values in respect to the origin. While movements down, right or back away from the camera are all positive in respect to the origin.

Code

Compared to Direct3D, it is actually a lot simpler to do rotation and translation in OpenGL; you just have to keep your head around your current states of your transformation matrices at all times. Let’s start off with the code for a cube from our last tutorial.

Keep in mind that the animation in this tutorial may not be the smoothest, and I will address as to why and how to fix it in the double buffering tutorial.

Now let’s get started. I’m going to aim for a cube that bounces up and down in our window, while rotating around on the spot. To do this, we are going to need three variables. The first, which is a Boolean called movingUp, is going to determine if our cube is moving up, or moving down. Next up we need something to store the location of our object along the y axis (up and down), I am going to create a float called yLocation, and initialize it to 0.0f. It is important that you initialize it to 0.0f as anything drawn is originally drawn at the location (0,0,0) unless you have called glTranslate before placing it. Finally I am going to use another float, this one called yRotationAngle to store the angle in degrees of rotation for our cube along the y axis. These variables are just examples for this tutorial, and so far have nothing to do with OpenGL itself.

bool movingUp = false; // Whether or not we are moving up or down
float yLocation = 0.0f; // Keep track of our position on the y axis.

float yRotationAngle = 0.0f; // The angle of rotation for our object

Next, jump down to your “main” method where we are going to need to add a new line which allows variables inside of the display method to be updated. Because we are using GLUT, GLUT likes us to place all of our variables to be updated into an “idle” method, which handles nothing but calculations, but this isn’t as efficient as it is led out to be. Whilst it is not written in bold anywhere, it is possible to use your “display” method as GLUT’s “idle” method, and if you read the GLUT API in detail, you can see that this is possible as rendering in the “idle” method is possible. But what does this mean? Well it means that not only are all our variables updated every time our “display” method is called as if they were in an “idle” method, but we can also get the maximum frame rate possible by utilizing the “idle” methods resources. It may not give too much of an improvement, but I like to push out every last frame possible on my system.

Anyway, enough talking, lets add this one line of code:

int main (int argc, char **argv) {
…
glutDisplayFunc(display); // Tell GLUT to use the method "display" for rendering

glutIdleFunc(display); // Tell GLUT to use the method "display" as our idle method as well

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

Good, now let’s get to updating our variables, so that we can then use them. We will do this at the end of our “display” method, just as a preference of mine, some people do all their processing at the start of their “display” method so that they can get their head around “these updates apply to this frame”, I look at it this way: “I have just done this, next I’m going to do this”. This code is quite basic, all we are doing is checking if the cube has gone below 3 units down or move above 3 units up, and toggling our Boolean variable to say if we need to move up or down, and then depending on this, we are either incrementing or decrementing our yLocation variable. I am also constantly increment my rotation angle, and when it gets above 360 degrees, or a full rotation, subtracting 360 degrees to reset it.

Just before the end of our “display” method, and after our glFlush method, place the lines:

if (movingUp) // If we are moving up
yLocation -= 0.005f; // Move up along our yLocation
else  // Otherwise
yLocation += 0.005f; // Move down along our yLocation

if (yLocation < -3.0f) // If we have gone up too far
movingUp = false; // Reverse our direction so we are moving down
else if (yLocation > 3.0f) // Else if we have gone down too far
movingUp = true; // Reverse our direction so we are moving up

yRotationAngle += 0.005f; // Increment our rotation value
if (yRotationAngle > 360.0f) // If we have rotated beyond 360 degrees (a full rotation)
yRotationAngle -= 360.0f; // Subtract 360 degrees off of our rotation

Now we are ready to start rotating and translating our object. This is extremely complicated, so give me some time to build it up.

Go back into your display method, and look for the lines glTranslatef(0.0f, 0.0f, -5.0f); and glutWireCube(2.0f); and make some space.

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

// Space for translation and rotation code

glutWireCube(2.0f); // Render the primitive
…
}

Great, make sure you have plenty of room, because the next two lines… Wait, the next *two* lines? Yes, I’m not joking, it only takes two lines, one the translation and the other for our rotation.

The only thing you need to make sure of here is that you do these calls in the correct order. If you translate and then rotation, the object will move into position and then rotate on the spot. If you rotate first, and then translate, your object will translate to its new position, but will then rotate in a giant circle around its starting position. To get the movement we described, add the following lines into the space you created above:

glTranslatef(0.0f, yLocation, 0.0f); // Translate our object along the y axis

glRotatef(yRotationAngle, 0.0f, 1.0f, 0.0f); // Rotate our object around the y axis

In OpenGL, this is all it takes to making your object rotate on the spot, and move, in this case up and down. It’s quite simple; the only tricky thing is keeping track of all your objects when you start working with fairly large complex scenes. If you try adding several objects in at the moment and moving them separately, you may have some trouble as OpenGL works on states and each translation and rotation is added to the previous. For getting around this, look at my tutorial on popping and pushing matrices J

If you have any questions, as usual 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)

bool movingUp = false; // Whether or not we are moving up or down
float yLocation = 0.0f; // Keep track of our position on the y axis.

float yRotationAngle = 0.0f; // The angle of rotation for our object

void keyOperations (void) {
if (keyStates[GLUT_KEY_LEFT]) { // If the left arrow key has been pressed
// Perform left arrow 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

glTranslatef(0.0f, yLocation, 0.0f); // Translate our object along the y axis

glRotatef(yRotationAngle, 0.0f, 1.0f, 0.0f); // Rotate our object around the y axis

glutWireCube(2.0f); // Render the primitive

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

if (movingUp) // If we are moving up
yLocation -= 0.005f; // Move up along our yLocation
else  // Otherwise
yLocation += 0.005f; // Move down along our yLocation

if (yLocation < -3.0f) // If we have gone up too far
movingUp = false; // Reverse our direction so we are moving down
else if (yLocation > 3.0f) // Else if we have gone down too far
movingUp = true; // Reverse our direction so we are moving up

yRotationAngle += 0.005f; // Increment our rotation value

if (yRotationAngle > 360.0f) // If we have rotated beyond 360 degrees (a full rotation)
yRotationAngle -= 360.0f; // Subtract 360 degrees off of our rotation
}

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 ("You’re first OpenGL Window"); // Set the title for the window

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

glutIdleFunc(display); // Tell GLUT to use the method "display" as our idle method as well

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
}
VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 9.6/10 (19 votes cast)
VN:F [1.9.3_1094]
Rating: +9 (from 9 votes)

6. OpenGL Cube (Version 2.0)

Posted on : 25-03-2010 | By : Swiftless | In : OpenGL

Tags: , , , , , ,

3

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 ("You’re 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
}
VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 7.8/10 (16 votes cast)
VN:F [1.9.3_1094]
Rating: +4 (from 6 votes)

5. OpenGL Color (Version 2.0)

Posted on : 25-03-2010 | By : Swiftless | In : OpenGL

Tags: , , , ,

7

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 ("You’re 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
}
VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 8.5/10 (11 votes cast)
VN:F [1.9.3_1094]
Rating: +3 (from 5 votes)

4. OpenGL Primitives – Square (Version 2.0)

Posted on : 25-03-2010 | By : Swiftless | In : OpenGL

Tags: , , , , ,

11

Introduction

Drawing shapes is one of those crucial things we do in OpenGL, because if we don’t draw anything, we don’t see anything. This tutorial was originally very simple, we drew a simple square, but I am going to extend it further and actually show how a bunch of different primitive types work, but don’t worry, we will still get to draw our square.

Different Drawing Types

OpenGL provides us with several different types of shapes that we can draw in order to get the geometry we want on the screen. In brief, they are:

  • GL_LINES
  • GL_LINE_STRIP
  • GL_LINE_LOOP
  • GL_POINTS
  • GL_POLYGON
  • GL_QUADS
  • GL_QUAD_STRIP
  • GL_TRIANGLES
  • GL_TRIANGLE_FAN
  • GL_TRIANGLE_STRIP

Let me give you a brief rundown of these shapes.

GL_LINES

As the name implies, this draws a line from one point to another in 3D space.

GL_LINE_STRIP

A line strip is a series of lines, where each point in the line has a point before it and after it, except for the end points. This is useful if you want to draw a series of lines, maybe you want to draw a circle and a circle is a set of lines.

GL_LINE_LOOP

This is similar to the GL_LINE_STRIP, except the end points double back to each other. So the first point will automatically connect to the end point via one line.

GL_POINTS

Draws a series of points in 3D space, their size can also be changed.

GL_POLYGON

A polygon is a 3D shape with any number of vertices, it is a filled surface.

GL_QUADS

A quad is similar to a polygon, but it limits the number of vertices to 4. This allows OpenGL to break it up into two triangles quite simply for faster processing. In short, a quad is a shape with 4 sides.

GL_QUAD_STRIP

A quad strip is a line of quads, where each quad shares two vertices with the quad before, and after it.

GL_TRIANGLES

Triangles are the ultimate shape in 3D geometry, this is because you can quickly and efficiently calculate how to fill them. GL_TRIANGLES takes a series of 3 vertices; each 3 vertices describe the points for a triangle.

GL_TRIANGLE_FAN

A triangle fan has one central vertex, and all other vertices form triangles extending from this point. Very useful for drawing filled circles.

GL_TRIANGLE_STRIP

A triangle strip is similar to a quad strip and a line strip, but it uses triangles, where two of the three vertices are shared with a triangle before and after itself.

Coding

So let’s stop babbling and get on to drawing a square. I am going to implement a new method, in order to keep our code nice and tidy. This method will be called renderPrimitive and will take no parameters.

void renderPrimitive (void) {

}

Now inside of our display method, we are going to want to call this, so before our glFlush line, make a call to render Primitive.

void display (void) {
…
renderPrimitive(); // Render the primitive
glFlush(); // Flush the OpenGL buffers to the window
}

Ok, good, we have a method we can fill to draw our shape, and we are calling it in our render loop. Next up, we aren’t going to go straight to drawing our shape, but we are going to add a line above our renderPrimitive call, and I’ll explain why. The default position for the camera in OpenGL is at the world origin, which is (0, 0, 0) in 3D space. Because we have a near plane at 1.0, anything drawn between the values of 0.0 and 1.0 on the z axis will be culled automatically. In other words, it won’t be drawn. In order to make sure we can see our shape, instead of positioning further along the z-axis when I set the vertices, I am going to move the entire scene back 5 units, so anything we draw at (0, 0, 0) will actually be drawn at (0, 0, 5). This may sound a little complicated, but trust me on this, and it will be explained a little more in the camera tutorial as the camera tutorial consists of 4 calls we do, before any of our rendering, to make sure we can see what we want.

Now, you can go ahead and add a line before our call to renderPrimitive which will translate (move) our scene 5 units in front of us. This is done with a call to glTranslate which takes three parameters, each one relating to how much we want to move everything on the x, y and z axis.

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
renderPrimitive(); // Render the primitive
glFlush(); // Flush the OpenGL buffers to the window
}

And finally everything is now set up for us to actually draw our square. When we want to tell OpenGL we are drawing some geometry, we need to make two calls, one at the start to tell OpenGL we now want to draw a shape, and one at the end, telling OpenGL we have finished drawing our shape.

These calls are glBegin and glEnd, relating to the beginning and the ending of our shape drawing, and glBegin takes one of the geometry types I mentioned earlier as a parameter. Because we are drawing a square, I am going to settle for GL_QUADS, although it would be more efficient to go for a GL_TRIANGLE_STRIP and supply 5 vertices to OpenGL to get the performance of triangles, I am going for simplicity and using only 4 vertices for a quad.

void renderPrimitive (void) {
glBegin(GL_QUADS); // Start drawing a quad primitive
glEnd();
}

At the moment, OpenGL will happily accept this code, but we won’t see anything on the screen. This is because we need to supply the vertex data for each corner of the quad to OpenGL. To make a call to create a vertex we use glVertex. glVertex can take either two or three parameters, and the types for the parameters can change, depending on the type of glVertex call. For example, if we want to draw a 2D vertex using float values, we would call glVertex2f. If we want to create a 3D vertex using double values, we would call glVertex3d. The same also works for integer values, and even arrays of data.

To be clear, the centre of the window, because I have only moved the camera back, is at the location (0, 0, 0). To draw our quad, we are going to create 4 vertices that revolve around this point. I am first going to declare the bottom left corner, followed by the top left, top right and bottom right. This is because it makes it simple to follow how texture coordinates will be assigned later on, as they go in this order.

In between our glBegin and glEnd calls, create the vertex calls like so:

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

You should now be able to compile and run this, and have it draw a white square in the middle of your window.

Go ahead and experiment with the other geometry types. You should be able to create the square, both filled and outlined, using any of the geometry types above.

If you have any questions, please email me at swiftless@gmail.com

Here are some examples of other geometry types:

Points

void renderPrimitive (void) {
glPointSize(20.0f);
glBegin(GL_POINTS); // Start drawing a point 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();
}

Line Loop

void renderPrimitive (void) {
glBegin(GL_LINE_LOOP); // Start drawing a line 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();
}

Triangle Strips

void renderPrimitive (void) {
glBegin(GL_TRIANGLE_STRIP); // Start drawing a triangle strip primitive
// The first triangle
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
// The end of the second triangle
glVertex3f(1.0f, -1.0f, 0.0f); // The bottom right corner
glVertex3f(-1.0f, -1.0f, 0.0f); // The bottom left corner
glEnd();
}

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[GLUT_KEY_LEFT]) { // If the left arrow key has been pressed
// Perform left arrow key operations
}
}

void renderPrimitive (void) {
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 ("You’re 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
}
VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 8.6/10 (17 votes cast)
VN:F [1.9.3_1094]
Rating: +7 (from 7 votes)

3. OpenGL Keyboard Interaction (Version 2.0)

Posted on : 25-03-2010 | By : Swiftless | In : OpenGL

Tags: , , , , ,

18

Introduction

The keyboard is one of those things that is essential to computer gaming, and computer use in general. Could you imagine trying to type with the mouse? Or the number of buttons that would be required on a mouse to allow for movement *and* shooting in a First Person Shooter? The good news is that keyboard interaction, thanks to GLUT, is an extremely easy thing to handle. I am going to look at 2 different GLUT methods for key presses, one for when a key is first pressed, and one for when a key is released. I will then be showing how to do some key buffering to allow multiple key presses at once.

Coding

Key Press

To get started with the keyboard, just like we created display and reshape methods for GLUT to use, we are going to need to create another method. The first method we are going to deal with is the key pressed method; this method will tell us which keys are currently pressed.

I am going to name this method keyPressed and GLUT states that it has 3 parameters, one for the key that is currently pressed, and two more that give us the location of the mouse when the key was pressed.

void keyPressed (unsigned char key, int x, int y) {
}

Now that we have an empty method, let’s go ahead and give this information to GLUT to use. Down in our main method, we will access the glutKeyboardFunc method and supply it with our method.

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

And that is pretty much all there is to it.

In order to access they keys pressed, inside your keyPressed method you can use either a switch statement or an ‘if’ statement, which checks they key variable against which ASCII character you want to check, and it will look something like this:

If (key == ‘a’) { // If they ‘a’ key was pressed
// Perform action associated with the ‘a’ key
}

Key Up

The key up function registers when a key is released. This can be very useful for setting some value when the key is first pressed, and wanting to keep that value until the key is released. Once again, as this is handled by GLUT, we will need to go and create a method to handle this, and just like the keyPressed method, this one will take in 3 parameters. These three parameters are exactly the same as 3 in the keyPressed method. But we are going to call this method keyUp. So let’s go ahead and create a method for this.

void keyUp (unsigned char key, int x, int y) {
}

And once again we need to register this method with GLUT, and this time we will use the glutKeyboardUpFunc method.

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

To use the keyUp method, is exactly the same as using the keyPressed method, so we can call the exact same code if we wanted.

if (key == 'a') { // If they ‘a’ key was released
// Perform action associated with the ‘a’ key
}

Key Buffering

The next step is of course, to do some key buffering, which will allow us to handle multiple key presses later on in our OpenGL projects. As you might be aware, a char variable is the same as a byte and can take an integer value from 0 to 255. This is because a char variable has a size of 2^8, or 256. This allows us to handle up to 256 different keys on a keyboard, or the entire ASCII set of characters.

So let’s start off by creating an array of Boolean values that will hold the states of our keys. True will be pressed, and False will be not pressed. I’m going to call this variable keyStates as it is easy to understand.

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

And now in our keyPressed method, let’s add a new line, which will set the value of the key we have pressed. This just sets the current position in the array of keyStates, at the position of the currently pressed key, to true.

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

And now we just need to add almost the exact same code to the keyUp method we created earlier. Only this time, we will be setting the state of the current key to false, meaning it is no longer pressed.

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

All that is left now for us to learn is how to actually use this. The good news is that now that you have the key information, you can use it however you want; you just have to setup somewhere in your code to manage this. I’ll go through an example on this to get you started.

To do this, I am going to create another method, this time called keyOperations, where we are going to check for which keys have been pressed, and then perform their actions. This method doesn’t need to return anything, and doesn’t need to accept any parameters. Just declare it before your display() method, as we are actually going to call it from our display method.

void keyOperations (void) {
}

And as we are calling this from our display method, go ahead and call it from the very start of our display method, preferably before everything else. The reason I say to call it before everything else, is if you call it halfway through your rendering, then half of your render will be affected by any values updated by the key presses, and the other half of your render will not be affected, giving a mismatch and possible artifacts.

void display (void) {
keyOperations();
glClearColor(1.0f, 0.0f, 0.0f, 1.0f); // Clear the background of our window to red
…
}

Finally, we fill in our keyOperations method with a whole bunch of if statements to check if the keys we want are pressed, and then perform the required actions.

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

Special Keys

While all of the above is perfectly fine for using regular key presses, there are some keys you may want to use, for example, the arrow keys, which can be represented differently on multiple systems. Luckily, GLUT allows us to use these keys, as long as we call a different method to glutKeyboardFunc. Instead we must use glutSpecialFunc which checks for presses of special keys. For example, if we want to check if the left arrow has been pressed, we can use GLUT_KEY_LEFT. The best news is that the method you create to handle your special keys, will be almost identical to the glutKeyboardFunc method you created earlier. Below is an example of using special keys.

First off, create a new method which I am going to call keySpecial, which takes three parameters, all of them being an integer value, the first for the key pressed, and the second two are for the x and y position of the mouse at the time the method was called. And then call this method in our main method along with the rest of our key presses.

void keySpecial (int key, int x, int y) {

}

And then for the up function for special keys, declare a new method for handling the up event for special keys.

void keySpecialUp (int key, int x, int y) {

}
int main (int argc, char **argv) {
...
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

glutSpecialFunc(keySpecial); // Tell GLUT to use the method "keySpecial" for special key presses
glutSpecialUpFunc(keySpecialUp); // Tell GLUT to use the method "keySpecialUp" for special up key events

glutMainLoop(); // Enter GLUT's main loop
}

If you want to buffer these keys, you can create another array just like we did for regular key buffering, and dedicate this array to any special keys pressed.

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

After you create this array, make sure you set the values to true and false, just as you did in the regular key methods, and then create another method to control what happens when we press our special keys, I am calling mine keySpecialOperations, which already has code for checking if the left arrow key has been pressed.

void keySpecialOperations(void) {
if (keySpecialStates[GLUT_KEY_LEFT]) { // If the left arrow key has been pressed
// Perform left arrow key operations
}
}

Hopefully this has helped you get an understanding of how to manage key presses in GLUT and OpenGL so you can get some keyboard interaction going in the later tutorials.

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 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

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 ("You’re 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
}
VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 9.3/10 (22 votes cast)
VN:F [1.9.3_1094]
Rating: +10 (from 10 votes)

2. OpenGL Window Reshaping (Version 2.0)

Posted on : 25-03-2010 | By : Swiftless | In : OpenGL

Tags: , , , , ,

12

Introduction

In a poorly written OpenGL application, you may notice that when you resize your window, your geometry will not transform to match the size and aspect ratio of your new window size. Your geometry may stay the same size even though the window is smaller or larger and what we want is for our geometry to scale with our window. This is because when GLUT sets up our window, it will initially set some default values for us, but GLUT doesn’t keep track of this information as the window changes, and for good reasons, every application has different needs, and there are no default magic values for everyone.

To fix this, we need to tell GLUT how we want our scene to be rendered, and to do so, we need to understand a little more about OpenGL matrices, and matrices in 3D applications in general. Now there are three main matrices in OpenGL, those being the Projection Matrix, Model View Matrix and the Texture Matrix.

Projection Matrix

The Projection Matrix, just like most matrices in 3D is a 4×4 matrix. This matrix provides the information needed to map a 3D scene to a 2D plane. In the case of OpenGL, this 2D plane is known as our Colour Buffer and this stores the image that we see rendered to our GLUT window, although rendering of the Colour Buffer to a window is not required for off-screen rending. In order to set up our Projection Matrix, we need to tell OpenGL the angle in degrees of our field of view, the aspect ratio for our window which will be our 2D rendering plane, and the near and far planes that bound our render.

Model View Matrix

The next main matrix is the Model View Matrix, which is also known as your Transformation Matrix. This matrix tells us the location and rotation of our geometry placement at any point in time. If you want to move an object, you will be modifying your Model View Matrix, without even knowing it.

Texture Matrix

The Texture Matrix is something you usually don’t want to touch. This is similar to the Model View Matrix as it is also a Transformation Matrix, but it is used for manipulation the position and rotation of textures in texture space. Personally I have only ever used this as a spare matrix when passing information through to GLSL shaders, but in fixed function rendering (standard OpenGL), you won’t want to touch this unless you have a specific reason.

Coding

So let’s now take a look at setting up how to reshape our window.

If you are following through my tutorials, each one will build upon another, and this one builds on top of the first tutorial on creating a window with GLUT. So for this tutorial you will want to open up the code from the previous tutorial.

Now go ahead, and create a new method called “reshape” which takes in two integer values and returns a void. The two incoming parameters will be sent via GLUT, and will contain the width and the height of the window at the point in time that it is called.

It should look something like this:

void reshape (int width, int height) {
}

Then down inside the main method, we need to let GLUT know which method to use for our reshaping, this is done almost identically to how we told GLUT to use our display() method.  After the line:

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

Add the line:

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

Now that GLUT knows which method to call, let’s fill it in so that it actually does something.

The first thing we are going to do is tell OpenGL the size of our viewport (the 2D plane) that we want to render to. We are going to tell OpenGL to start at (0, 0), which corresponds to the bottom left of our window, and then we will tell it to take the size (width, height), which will give us the top right of our window.

glViewport(0, 0, (GLsizei)width, (GLsizei)height); // Set our viewport to the size of our window

Once we have setup the size of our viewport, we need to switch to our Projection Matrix so that we can setup how our scene is rendered.

glMatrixMode(GL_PROJECTION); // Switch to the projection matrix so that we can manipulate how our scene is viewed

Now that we are in the correct mode, we are going to reset our Projection Matrix to the identity matrix so that we don’t cause any artefacts.

Forgetting to reset matrices is a big cause of unusual rendering as OpenGL adds on the previous matrix every time something is called. In the case of setting the Projection Matrix, it would be like trying to apply the projection on to the current projection.

glLoadIdentity(); // Reset the projection matrix to the identity matrix so that we don't get any artifacts (cleaning up)

Now we are ready for the core of this method. The following line will setup the parameters for our view, such as the field of view, aspect ratio and the near and far planes. The first variable that I am going to set is the field of view (FOV), which I am going to set to 60 degrees. This gives us a viewing angle of 30 degrees to the left, and 30 degrees to the right.

The next value after that is the aspect ratio of our window, which is calculated by dividing the width of our window by the height. The last two values are the near and far plane, and I am going to set them to 1.0 and 100.0 respectively. This means that anything with a position less than 1.0 unit (away from the camera) won’t be drawn and anything with a position greater than 100.0 units (away from the camera) won’t be drawn.

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

The very last thing we need to do in our method is switch back to the Model View Matrix. If we forget to do this, then we will be trying to position our geometry according to our Projection Matrix, and we do not want this.

glMatrixMode(GL_MODELVIEW); // Switch back to the model view matrix, so that we can start drawing shapes correctly

And that should do it, just make sure everything compiles, and when we add some geometry, you can see this method in action.

It doesn’t seem like much, but this is an extremely important method. You will want absolute control over your field of view, and near and far planes in most applications you write.

If you have any questions, please email me at swiftless@gmail.com

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

void display (void) {
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
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
}

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 ("You’re 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 rendering
glutMainLoop(); // Enter GLUT's main loop
}
VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 9.0/10 (36 votes cast)
VN:F [1.9.3_1094]
Rating: +12 (from 12 votes)
Improve the web with Nofollow Reciprocity.