4. OpenGL Primitives – Square (Version 2.0)
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 ("Your first OpenGL Window"); // Set the title for the window glutDisplayFunc(display); // Tell GLUT to use the method "display" for rendering glutReshapeFunc(reshape); // Tell GLUT to use the method "reshape" for reshaping glutKeyboardFunc(keyPressed); // Tell GLUT to use the method "keyPressed" for key presses glutKeyboardUpFunc(keyUp); // Tell GLUT to use the method "keyUp" for key up events glutMainLoop(); // Enter GLUT's main loop }
Thanks a lot for the wonderful tutorials, the easiest and the most descriptive of tutorials available on the Net.
Hello swiftless!,
I’m glad, i found your website. Thanks alot 🙂 … I have a problem here, why is that my keyfunction doesn’t working?
thanks
Siti
gluPerspective() has been removed from GLU. Other than that, thanks for a great intro article.
For the different drawing types here is a quick image that can explain any person without reading tons of text :)….
http://www.cs.uregina.ca/Links/class-info/405/WWW/Lab2/glPrimitives.png
Thanks, I am getting started with OpenGL. I have bookmarked this site for reference. Btw – The colors and they way you layed it out makes it easy to read.
Thank you very much for putting up this site and the time you put into it.
Hello, these tutorials have been a big help! I didn’t feel like going through nehe’s window framework so I just read the lessons and apply them to projects. Some of his projects are converted to glut to which helps. Anyways, having some tutorials using glut makes it much easier to learn actual OpenGL code. I can always learn how to make my own window framework later.
I’ll hopefully get some working OpenGL games by the end of the week, I’ll post my progress if I have time. Thanks!
Hi Matt,
I’m glad it could help. This site started off back in the day as a means to show how to achieve certain effects, and has since grown into full fledged tutorials to show how to use the actual OpenGL code. In these tutorials, GLUT allows that, but in the OpenGL 3.x and 4.x tutorials, there is no GLUT equivalent at the time of writing (If there was, I simply didn’t hear of it).
Cheers,
Swiftless
Well I decided to go with learning the older versions because there seems to be more info and I’m sure when I decide to convert to the newer versions, it won’t be as hard.
Hey, want to say that I’ve been reading a book on OpenGL programming but your tutorials are much better.
I’ve also got a question: I wanted to test changing one of the coordinates of a vertex of the quad, so I declared the global variable ‘corner’. I set it to change when the key ‘a’ was pressed (add 0.01f to ‘corner’).
I’m getting unexpected behavior; the quad only changes if I click on the window (???). I tried eliminating the key presses and put the line “corner += 0.01f;” in the renderPrimitive function but the quad only changes when I rapidly click on the window. Any idea what the issue might be? Thanks.
Hi Michael,
At the end of your keypress function, you could include a call to tell OpenGL to update, possibly add glutPostRedisplay().
If that doesn’t work, is your window constantly losing focus?
Thanks,
Swiftless
I can’t see any quad there. O.o I did everything just as you did but I just can’t see any quads.
Hi Daniel,
It sounds like something is missing. The code I have provided, *will* show a quad, no matter what system you are on, as long as it supports OpenGL.
Cheers,
Swiftless
It seems like it had something to do with the positions. I edited the translate values a bit and got the cube visible.
It seems for some reason using this code that the line: if (keyStates[GLUT_KEY_LEFT]) always returns true.
It does also not change when I press the left key. It also does not seem to work with the ‘a’ key, and neither if I just enter the ascii code number.
Any ideas why this happens?
Got it working now – seems the booleans where set to have true as default.
Glut_KEY_LEFT is not working yet though. Only if I specify the ascii code from it, which is fine for me.
Hey Ruud,
I thought I had fixed this tutorial up, but apparently not.
GLUT_KEY_LEFT and other special keys don’t actually work with glutKeyboardFunc, they only work with glutSpecialFunc.
Cheers,
Swiftless
in later programmes also this particular line is creating a problem…wherein the line is not required i tried deleted it and tried to run the programmes and it was successful…can you jus check and let me noe becauz my other programmes are also not running in this tutorial…
all the errors that i am getting are related to this line
bool* keyStates = new bool[256];
missing ‘{‘ before ‘*’
‘new’ : undeclared identifier
initializer is not a constant
syntax error : missing ‘;’ before identifier ‘bool’
‘true’ : undeclared identifier
‘false’ : undeclared identifier
these are the errors displayed when i compile my code in VS2010 after complying it from here…
i am not able to compile the above code. its giving an error with the 4th line of your code…i am using VS2010 and GLUT.can you tell me what is going wrong ?
I am thinking of doing Something in OpenGL
A object for example a mobile which i can rotate and also rotate the view.how many tutorials should i go through so as to do this project can u suggest any good e-book..mail me if possible thank you…
Hi Varun,
What is the error you are getting? I have all of the version 2.0 tutorials successfully running in VS2010. As long as you have created a standard c++ win32 console application, everything should be fine.
You will want to look at the third camera tutorial for rotating around an object. But I don’t have any tutorials on model loading.
Cheers,
Swiftless
good tutorial,
few doubts?
in the example you have declared viewport equal to window size.. e.g. my window size – 100, 100. so viewport will be equal to 0-100 width and 0-100 height.
so why not point have coordinateds like
glVertex3f(-10.0f, -10.0f, 0.0f);
why it is
glVertex3f(-1.0f, -1.0f, 0.0f);
why the coordinates range is ~-2.5 to 2.5.
Regards,
Aman
Hi Aman,
This has to do with the maths behind projection matrices. It’s a little complicated to say off the top of my head, so if you fully want to understand it, have a quick search around on Google, there is a lot information around.
Also, I’ll point out that OpenGL does not use it’s measurement in pixels, it uses units which can be any length depending on the implementation.
You will also notice, that the further back into the scene an object is, the more you can move it to the left/right and top/bottom and still see it because of the perspective view.
Cheers,
Donald
First of all: Really great tutorials! 🙂
My question: Why is there a “f” behind every number?
glTranslatef(0.0f, 0.0f, -5.0f);
I learned to write this way:
glTranslatef(0.0, 0.0, -5.0);
I thought it is set to float by the first “f”.
Greetings
Hey Illu,
The glTranslatef with an f on the end is just the OpenGL method that takes float values. Putting an f on the end, is a c++ way of saying this is a float and not a double. Some languages need you to declare the f on the end to distinguish between a float and a double.
Cheers,
Swiftless