OpenGL Programming/GLStart/Tut3

Tutorial 3: Drawing Primitives

edit

Primitives 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

edit

The 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

edit

Lets 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

edit

I 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

edit

Triangles 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

edit

Polygons 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

edit

Using 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

edit

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