Syllabus   Blank Homework   Quizzes  
Notes   Labs   Scores   Blank


Lecture Notes
Dr. Tong Yu, Sept. 2013
All the materials presented here are adopted from the textbook and the listed references.
    1. Introduction
    2. Line Drawing
    3. Drawing Objects
    4. More Drawing Tools
    5. Vertex Array
    6. Normal Vectors and Polygonal Models of Surfaces
    7. Viewing I -- Affine Transformations
    8. Viewing II -- Projections
    9. Color
    10. Lighting
    11. Blending, antialiasing, fog ..
    12. Display Lists, Bitmaps and Images
    Appendix. Games and SDL

    Vertex Array and Vertex Buffer Object

    1. Vertex Arrays

    2. Function calls are expensive

    3. If use glBegin() .. glEnd(), shared vertices have to be specified again and again.
      Example:
      • A cube has 6 faces, 8 vertices,
      • each face needs 4 vertices to specify
      • will process a total of 24 vertices though 8 would be enough
      Six sides, eight shared vertices

    4. OpenGL has vertex array routines to process arrays of vertices with fewer function calls and make programming more efficient and effective

    5. Three steps in using vertex array:
      1. Enabling Arrays

        void glEnableClientState(GLenum array)
        Specifies the array to enable.
        Acceptable Symbolic constants:
        GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_INDEX_ARRAY, GL_NORMAL_ARRAY, GL_TEXTURE_COORD_ARRAY, and GL_EDGE_FLAG_ARRAY

        Example:
        If use lighting, you want to define a surface normal for every vertex. To use vertex arrays for that case, you activate both the surface normal and vertex coordinate arrays:

          glEnableClientState(GL_NORMAL_ARRAY);
          glEnableClientState(GL_VERTEX_ARRAY);

        Can be turned off by:

          glDisableClientState(GL_NORMAL_ARRAY);

      2. Specifying Data for the Arrays

        void glVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
        Specifies where spatial coordinate data can be accessed. pointer is the memory address of the first coordinate of the first vertex in the array. type specifies the data type (GL_SHORT, GL_INT, GL_FLOAT, or GL_DOUBLE) of each coordinate in the array. size is the number of coordinates per vertex, which must be 2, 3, or 4. stride is the byte offset between consecutive vertexes. If stride is 0, the vertices are understood to be tightly packed in the array.

        void glColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);

        void glIndexPointer(GLenum type, GLsizei stride, const GLvoid *pointer);

        void glNormalPointer(GLenum type, GLsizei stride, const GLvoid *pointer);

        void glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);

        void glEdgeFlagPointer(GLsizei stride, const GLvoid *pointer);

        Table Vertex Array Sizes (Values per Vertex) and Data Types

        CommandSizes     Values for type Argument
        glVertexPointer 2, 3, 4     GL_SHORT, GL_INT, GL_FLOAT, GL_DOUBLE
        glNormalPointer3 GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT, GL_DOUBLE
        glColorPointer3, 4 GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT, GL_FLOAT, GL_DOUBLE
        glIndexPointer1 GL_UNSIGNED_BYTE, GL_SHORT, GL_INT, GL_FLOAT, GL_DOUBLE
        glTexCoordPointer1, 2, 3, 4 GL_SHORT, GL_INT, GL_FLOAT, GL_DOUBLE
        glEdgeFlagPointer1 no type argument (type of data must be GLboolean)

        Example:
        Enabling and Loading Vertex Arrays:
        static GLint vertices[] = {25, 25,
                                  100, 325,
                                  175, 25,
                                  175, 325,
                                  250, 25,
                                  325, 325};
        static GLfloat colors[] = {1.0, 0.2, 0.2,
                                  0.2, 0.2, 1.0,
                                  0.8, 1.0, 0.2,
                                  0.75, 0.75, 0.75,
                                  0.35, 0.35, 0.35,
                                  0.5, 0.5, 0.5};
        
        glEnableClientState (GL_COLOR_ARRAY);
        glEnableClientState (GL_VERTEX_ARRAY);
        
        glColorPointer (3, GL_FLOAT, 0, colors);
        glVertexPointer (2, GL_INT, 0, vertices);
        	

        Speed up using vertex buffer object, which stores data in video card

        Stride:
        tells OpenGL how to access the data you provide in your pointer value
        its value should be the number of bytes between the starts of two successive pointer elements, or zero, which is a special case

        static GLfloat mixed_data[] =
              {1.0, 0.2, 1.0, 100.0, 100.0, 0.0,
               1.0, 0.2, 0.2, 0.0, 200.0, 0.0,
               1.0, 1.0, 0.2, 100.0, 300.0, 0.0,
               0.2, 1.0, 0.2, 200.0, 300.0, 0.0,
               0.2, 1.0, 1.0, 300.0, 200.0, 0.0,
               0.2, 0.2, 1.0, 200.0, 100.0, 0.0};
        	

        Stride allows a vertex array to access its desired data at regular intervals in the array.

        	
        glColorPointer (3, GL_FLOAT, 6 * sizeof(GLfloat), mixed_data);
        	

        For the vertex coordinate pointer, you need to start from further in the array, at the fourth element of mixed_data.

        
        	glVertexPointer(3, GL_FLOAT,6*sizeof(GLfloat), &mixed_data[3]);
        
        	

      3. Dereferencing and Rendering

        Dereferencing a Single Array Element

          void glArrayElement(GLint ith)
          Obtains the data of one (the ith) vertex for all currently enabled arrays. For the vertex coordinate array, the corresponding command would be glVertex[size][type]v(), where size is one of [2,3,4], and type is one of [s,i,f,d] for GLshort, GLint, GLfloat, and GLdouble respectively. Both size and type were defined by glVertexPointer(). For other enabled arrays, glArrayElement() calls glEdgeFlagv(), glTexCoord[size][type]v(), glColor[size][type]v(), glIndex[type]v(), and glNormal[type]v(). If the vertex coordinate array is enabled, the glVertex*v() routine is executed last, after the execution (if enabled) of up to five corresponding array values.

        Example:
        glEnableClientState (GL_COLOR_ARRAY);
        glEnableClientState (GL_VERTEX_ARRAY);
        glColorPointer (3, GL_FLOAT, 0, colors);
        glVertexPointer (2, GL_INT, 0, vertices);
        
        glBegin(GL_TRIANGLES);
        glArrayElement (2);
        glArrayElement (3);
        glArrayElement (5);
        glEnd();
        

        When executed, the latter five lines of code has the same effect as

        glBegin(GL_TRIANGLES);
        glColor3fv(colors+(2*3));
        glVertex2iv(vertices+(2*2));
        glColor3fv(colors+(3*3));
        glVertex2iv(vertices+(3*2));
        glColor3fv(colors+(5*3));
        glVertex2iv(vertices+(5*2));
        
        glEnd();
        

        Dereferencing a List of Array Elements

          void glDrawElements(GLenum mode, GLsizei count, GLenum type, void *indices );

          almost has the same effect as:
           
          int i;
          glBegin (mode);
          for (i = 0; i < count; i++)
             glArrayElement(indices[i]);
          glEnd();
          

          mode can be GL_POLYGON, GL_POINTS, ..
           
          Cube with Numbered Vertices

        Example:   Two Ways to Use glDrawElements()

        static GLubyte frontIndices[] = {4, 5, 6, 7};
        static GLubyte rightIndices[] = {1, 2, 6, 5};
        static GLubyte bottomIndices[] = {0, 1, 5, 4};
        static GLubyte backIndices[] = {0, 3, 2, 1};
        static GLubyte leftIndices[] = {0, 4, 7, 3};
        static GLubyte topIndices[] = {2, 3, 7, 6};
        
        glDrawElements(GL_QUADS, 4, GL_UNSIGNED_BYTE, frontIndices);
        glDrawElements(GL_QUADS, 4, GL_UNSIGNED_BYTE, rightIndices);
        glDrawElements(GL_QUADS, 4, GL_UNSIGNED_BYTE, bottomIndices);
        glDrawElements(GL_QUADS, 4, GL_UNSIGNED_BYTE, backIndices);
        glDrawElements(GL_QUADS, 4, GL_UNSIGNED_BYTE, leftIndices);
        glDrawElements(GL_QUADS, 4, GL_UNSIGNED_BYTE, topIndices);
        

        Or better still, crunch all the indices together

        static GLubyte allIndices[] = {4, 5, 6, 7, 1, 2, 6, 5, 
        	0, 1, 5, 4, 0, 3, 2, 1, 
        	0, 4, 7, 3, 2, 3, 7, 6};
        
        glDrawElements(GL_QUADS, 24, GL_UNSIGNED_BYTE, allIndices);
        	

        Note: It is an error to encapsulate glDrawElements() between a glBegin()/glEnd() pair.

          void glDrawArrays(GLenum mode, GLint first, GLsizei count );
        Almost same as
          	glBegin( mode );
          	for ( i = 0; i < count; ++i )
          	  glArrayElement ( first + i );
          	glEnd();
          	

        Interleaved Arrays

        void glInterleavedArrays ( GLenum format, GLsizei stride, void *pointer );

        e.g. glInterleavedArrays( GL_C3F_V3F, 0, mixed_data );

          This call enables GL_COLOR_ARRAY and GL_VERTEX_ARRAY. It disables other ..ARRAYs like GL_NORMAL_ARRAY, GL_SECONDARY_ARRAY, ..
    6. An Example:

      /*
       *  varray.cpp
       *  This program demonstrates vertex arrays.
       */
      #include <GL/glut.h>
      #include <stdlib.h>
      #include <stdio.h>
      
      #ifdef GL_VERSION_1_1
      #define POINTER 1
      #define INTERLEAVED 2
      
      #define DRAWARRAY 1
      #define ARRAYELEMENT  2
      #define DRAWELEMENTS 3
      #endif
      
      int setupMethod = POINTER;
      int method = DRAWARRAY;
      
      void setupPointers(void)
      {
         static GLint vertices[] = {25, 25,
                             100, 325,
                             175, 25,
                             175, 325,
                             250, 25,
                             325, 325};
         static GLfloat colors[] = {1.0, 0.2, 0.2,
                             0.2, 0.2, 1.0,
                             0.8, 1.0, 0.2,
                             0.75, 0.75, 0.75,
                             0.35, 0.35, 0.35,
                             0.5, 0.5, 0.5};
      
         glEnableClientState (GL_VERTEX_ARRAY);
         glEnableClientState (GL_COLOR_ARRAY);
      
         glVertexPointer (2, GL_INT, 0, vertices);
         glColorPointer (3, GL_FLOAT, 0, colors);
      }
      
      void setupInterleave(void)
      {
         static GLfloat mixed_data[] =
            {1.0, 0.2, 1.0, 100.0, 100.0, 0.0,
             1.0, 0.2, 0.2, 0.0, 200.0, 0.0,
             1.0, 1.0, 0.2, 100.0, 300.0, 0.0,
             0.2, 1.0, 0.2, 200.0, 300.0, 0.0,
             0.2, 1.0, 1.0, 300.0, 200.0, 0.0,
             0.2, 0.2, 1.0, 200.0, 100.0, 0.0};
         
         glInterleavedArrays (GL_C3F_V3F, 0, mixed_data);
      }
      
      void init(void) 
      {
         glClearColor (0.0, 0.0, 0.0, 0.0);
         glShadeModel (GL_SMOOTH);
         setupPointers ();
      }
      
      void display(void)
      {
         glClear (GL_COLOR_BUFFER_BIT);
      
         if (method == DRAWARRAY) 
            glDrawArrays (GL_TRIANGLES, 0, 6);
         else if (method == ARRAYELEMENT) {
            glBegin (GL_TRIANGLES);
            glArrayElement (2);
            glArrayElement (3);
            glArrayElement (5);
            glEnd ();
         }
         else if (method == DRAWELEMENTS) {
            GLuint indices[4] = {0, 1, 3, 4};
      
            glDrawElements (GL_POLYGON, 4, GL_UNSIGNED_INT, indices);
         }
         glFlush ();
      }