OpenGL Programming/GLStart/Tut3
Tutorial 3: Drawing Primitives
editPrimitives are basic shapes that you can easily draw. It can be a triangle, a square, or even a single point. In this lesson we are going to learn how to draw some basic primitives including: points, triangles, and different polygons.
Immediate Mode
editThe easiest way to do drawing in OpenGL is using the Immediate Mode. For this, you use the glBegin() function which takes as one parameter the “mode” or type of object you want to draw.
Here is a list of the possible modes and what they mean:
GL_POINTS | Draws points on screen. Every vertex specified is a point. |
---|---|
GL_LINES | Draws lines on screen. Every two vertices specified compose a line. |
GL_LINE_STRIP | Draws connected lines on screen. Every vertex specified after first two are connected. |
GL_LINE_LOOP | Draws connected lines on screen. The last vertex specified is connected to first vertex. |
GL_TRIANGLES | Draws triangles on screen. Every three vertices specified compose a triangle. |
GL_TRIANGLE_STRIP | Draws connected triangles on screen. Every vertex specified after first three vertices creates a triangle. |
GL_TRIANGLE_FAN | Draws connected triangles like GL_TRIANGLE_STRIP, except draws triangles in fan shape. |
GL_QUADS | Draws quadrilaterals (4 – sided shapes) on screen. Every four vertices specified compose a quadrilateral. |
GL_QUAD_STRIP | Draws connected quadrilaterals on screen. Every two vertices specified after first four compose a connected quadrilateral. |
GL_POLYGON | Draws a polygon on screen. Polygon can be composed of as many sides as you want. |
When you are done drawing all the vertices of the specific primitive, you put in the next line the glEnd() function which ends drawing of that primitive.
Drawing Points
editLets do an example with the simplest mode, the GL_POINTS. When drawing points using OpenGL, the default size of the points is 1 pixel wide and high. This would be very hard to see when you run the program. To edit the size of the point you want to draw, you use the glPointSize() function which takes as one parameter the size of the point you want.
Now in the Render() function, before you write the glBegin() code, we will set the point size to be 10 pixels in size:
glPointSize(10.0f);
After that, any drawing of points will be drawn 10 pixels wide and high. Now write the glBegin() function with the GL_POINTS mode parameter. Then after that specify the vertices you want to use using the glVertex3f() function. For this example, we want the upper – right corner (1.0,1.0,0.0) and the lower – left corner (-1.0,-1.0,0.0) of the screen to have a point. After drawing those two points, make sure to end the drawing with the glEnd() function:
glBegin(GL_POINTS); //starts drawing of points glVertex3f(1.0f,1.0f,0.0f);//upper-right corner glVertex3f(-1.0f,-1.0f,0.0f);//lower-left corner glEnd();//end drawing of points
Here is the whole render function for your reference followed by a sample output. The whole code for this section of the tutorial can be found in the downloadable files. This example is called “points”:
void Render() { //clear color and depth buffer glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity();//load identity matrix glTranslatef(0.0f,0.0f,-4.0f);//move forward 4 units glColor3f(0.0f,0.0f,1.0f); //blue color glPointSize(10.0f);//set point size to 10 pixels glBegin(GL_POINTS); //starts drawing of points glVertex3f(1.0f,1.0f,0.0f);//upper-right corner glVertex3f(-1.0f,-1.0f,0.0f);//lower-left corner glEnd();//end drawing of points }
Drawing a Line Loop
editI would like to cover every single mode in the glBegin() function, but it would take up too much time and space. So I will cover the advanced ones and most likely cover the other ones when they are deemed useful.
A line loop requires at least two vertices. Every vertex specified after that is connected to the vertex specified before it and the first vertex specified. So if we put a vertex to the left of the window, to the right of the window, on top and on the bottom, we would have a rotated square:
Lets do this diagram in OpenGL. First we use the glBegin() function and pass the parameter of GL_LINE_LOOP to tell OpenGL we are going to start drawing a line loop. Then we pass the four vertices to create the rotated square. The first vertex being to the left of the window (-1.0f,0.0f,0.0f), second one being at the bottom of the window (0.0f,-1.0f,0.0f), third at the right of window (1.0f,0.0f,0.0f), and the fourth and last being at the top of the window (0.0f,1.0f,0.0f). Then we make sure to put in glEnd() to tell OpenGL we are done drawing the line loop:
glBegin(GL_LINE_LOOP);//start drawing a line loop glVertex3f(-1.0f,0.0f,0.0f);//left of window glVertex3f(0.0f,-1.0f,0.0f);//bottom of window glVertex3f(1.0f,0.0f,0.0f);//right of window glVertex3f(0.0f,1.0f,0.0f);//top of window glEnd();//end drawing of line loop
Following is the whole Render() function followed by a sample output. Look for the project file called “lineLoop” on the downloadable file for this chapter:
void Render() { //clear color and depth buffer glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity();//load identity matrix glTranslatef(0.0f,0.0f,-4.0f);//move forward 4 units glColor3f(0.0f,0.0f,1.0f); //blue color glBegin(GL_LINE_LOOP);//start drawing a line loop glVertex3f(-1.0f,0.0f,0.0f);//left of window glVertex3f(0.0f,-1.0f,0.0f);//bottom of window glVertex3f(1.0f,0.0f,0.0f);//right of window glVertex3f(0.0f,1.0f,0.0f);//top of window glEnd();//end drawing of line loop }
Drawing Triangles
editTriangles are composed of three vertices. For this example we are going to use the regular GL_TRIANGLES mode to draw two triangles side by side.
First we want a triangle to the left. So we need three vertices on the left side representing one triangle and three vertices on the right side of the window representing the second triangle. Note that you don’t need two glBegin() functions to draw two triangles. Since the mode GL_TRIANGLES is plural, it can handle more than one triangle in between one glBegin() and glEnd() function call:
Note that I wrote on the bottom – right corner of the diagram the coordinates of the vertices. Here is the code to draw these two triangles:
glBegin(GL_TRIANGLES);//start drawing triangles glVertex3f(-1.0f,-0.1f,0.0f);//triangle one first vertex glVertex3f(-0.5f,-0.25f,0.0f);//triangle one second vertex glVertex3f(-0.75f,0.25f,0.0f);//triangle one third vertex //drawing a new triangle glVertex3f(0.5f,-0.25f,0.0f);//triangle two first vertex glVertex3f(1.0f,-0.25f,0.0f);//triangle two second vertex glVertex3f(0.75f,0.25f,0.0f);//triangle two third vertex glEnd();//end drawing of triangles
Following is the whole Render() function for this example followed by a sample output. To view the whole code, please see the “triangle” project folder in the downloadable files:
void Render() { //clear color and depth buffer glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity();//load identity matrix glTranslatef(0.0f,0.0f,-4.0f);//move forward 4 units glColor3f(0.0f,0.0f,1.0f); //blue color glBegin(GL_TRIANGLES);//start drawing triangles glVertex3f(-1.0f,-0.25f,0.0f);//triangle one first vertex glVertex3f(-0.5f,-0.25f,0.0f);//triangle one second vertex glVertex3f(-0.75f,0.25f,0.0f);//triangle one third vertex //drawing a new triangle glVertex3f(0.5f,-0.25f,0.0f);//triangle two first vertex glVertex3f(1.0f,-0.25f,0.0f);//triangle two second vertex glVertex3f(0.75f,0.25f,0.0f);//triangle two third vertex glEnd();//end drawing of triangles }
Drawing Polygons
editPolygons consist of at least three vertices that, when connected, make up a shape. In this example we are going to be using the GL_POLYGON mode to draw a six – sided shape.
The GL_POLYGON mode allows you to draw a shape with any number of sides as you want. Since GL_POLYGON is a singular word (meaning no “S” at the end of the word), you can only draw one polygon between a glBegin() and glEnd() function call. Also, the last vertex you specify is automatically connected to the first vertex specified. And of course, since a polygon is a closed shape, like the triangle, the shape will be filled with your specified color (which for now is blue). Here is the diagram for our six – sided shape:
(note: this can't be used for concave polygons)
Here is the code to draw this polygon:
glBegin(GL_POLYGON);//begin drawing of polygon glVertex3f(-0.5f,0.5f,0.0f);//first vertex glVertex3f(0.5f,0.5f,0.0f);//second vertex glVertex3f(1.0f,0.0f,0.0f);//third vertex glVertex3f(0.5f,-0.5f,0.0f);//fourth vertex glVertex3f(-0.5f,-0.5f,0.0f);//fifth vertex glVertex3f(-1.0f,0.0f,0.0f);//sixth vertex glEnd();//end drawing of polygon
Following is the whole Render() function followed by a sample output. Look for the whole code in the “polygon” project folder on the included downloadable files:
void Render() { //clear color and depth buffer glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity();//load identity matrix glTranslatef(0.0f,0.0f,-4.0f);//move forward 4 units glColor3f(0.0f,0.0f,1.0f); //blue color glBegin(GL_POLYGON);//begin drawing of polygon glVertex3f(-0.5f,0.5f,0.0f);//first vertex glVertex3f(0.5f,0.5f,0.0f);//second vertex glVertex3f(1.0f,0.0f,0.0f);//third vertex glVertex3f(0.5f,-0.5f,0.0f);//fourth vertex glVertex3f(-0.5f,-0.5f,0.0f);//fifth vertex glVertex3f(-1.0f,0.0f,0.0f);//sixth vertex glEnd();//end drawing of polygon }
Display Lists
editUsing the OpenGL immediate mode has several drawbacks. For example, vertex data must be transferred on the fly to the graphics memory whenever drawing. This can be improved by using Display Lists. Display Lists essentially take a glBegin()/glEnd() command sequence and store that on the graphics card side in an efficient manner.
(todo: elaborate on that later, see [1] for some infos - glGenLists(), glNewList(), glEndList(), glCallList(), glDeleteLists())
Vertex Arrays and Vertex Buffers
editDisplay Lists also have drawbacks. Once compiled, Display Lists are static, and cannot be changed. Also, vertices shared by several primitives still need to be represented and transformed multiple times when drawing. This is very inefficient.
These problems are addressed by Vertex Arrays and Vertex Buffers. The idea is simply to use arrays to store vertex data. Using glDrawArrays(), primitives using these vertices can be drawn.
For storage of data in video memory, Vertex Buffers can be used (glGenBuffer(), glBindBuffer(), glBufferData(), glDeleteBuffers()). Two types of Vertex Buffers exist:
- GL_ARRAY_BUFFERs hold actual vertex data.
- GL_ELEMENT_ARRAY_BUFFERs hold indices to vertices stored in a separate GL_ARRAY_BUFFER and, thus, allow reusing vertices in several primitives.
(todo: elaborate on that later, example)