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

    Blending, Antialiasing, Fog and Polygon Offset

    We are what we repeatedly do.
    Excellence, then, is not an act, but a habit.
    Aristotle

    1. Transparency

    2. In normal rendering, we ignore the alpha value, the A in RGBA color.

    3. If we first enable blending, by

        glEnable( GL_BLEND );

      then the alpha value will have meaning.

        1 -- material opaque, hides everything behind

        0 -- material completely transparent and cannot be seen

    4. When we render only opaque polygons, the z-buffer for hidden surface removal is enough to render objects properly

    5. Blending model:

      • destination -- color buffer ( holds color info for display )

      • source -- polygon colors that we are working on

      • new destination color = combination of old destination color and source color


         Source Color 
         

        -----------→
             
        |
        |
        |
        |
        |
        |
        |
        |
        |
        |
        --------→
               
        ------------

         blending 
         
        |
        |
        |
        |
        |
        |
        |
        |

         Destination
         Color 
         

      • combine using source and destination factors

      • Suppose, at some point
          destination color = ( Rd, Gd, Bd, Ad )
          polygon color = ( Rs, Gs, Bs, As )
          destination factor = ( Dr, Dg, Db, Da )
          source factor = ( Sr, Sg, Sb, Sa )

        The blended color ( new destination color ) is

          ( RsSr + RdDr,   GsSg + GdDg,   BsSb + BdDb,   AsSa + AdDa )

          Each component is clamped to [0,1].

      • gl blending functions

        used to generate blending factors

        void glBlendFunc(GLenum sfactor, GLenum dfactor);
        Controls how color values in the fragment being processed (the source) are combined with those already stored in the framebuffer (the destination). The argument sfactor indicates how to compute a source blending factor; dfactor indicates how to compute a destination blending factor. The possible values for these arguments are explained in Table below. The blend factors are assumed to lie in the range [0,1]; after the color values in the source and destination are combined, they're clamped to the range [0,1].

        void glBlendFuncSeparate(GLenum srcRGB, GLenum destRGB, GLenum srcalpha, GLenum destalpha );
        Still use the table below but blending factors of RGB and A are considered separately.

        Constant

        Relevant Factor

        Computed Blend Factor

        GL_ZERO

        source or destination

        (0, 0, 0, 0)

        GL_ONE

        source or destination

        (1, 1, 1, 1)

        GL_DST_COLOR

        destination

        (Rd, Gd, Bd, Ad)

        GL_SRC_COLOR

        source

        (Rs, Gs, Bs, As)

        GL_ONE_MINUS_DST_COLOR

        source

        (1, 1, 1, 1)-(Rd, Gd, Bd, Ad)

        GL_ONE_MINUS_SRC_COLOR

        destination

        (1, 1, 1, 1)-(Rs, Gs, Bs, As)

        GL_SRC_ALPHA

        source or destination

        (As, As, As, As)

        GL_ONE_MINUS_SRC_ALPHA

        source or destination

        (1, 1, 1, 1)-(As, As, As, As)

        GL_DST_ALPHA

        source or destination

        (Ad, Ad, Ad, Ad)

        GL_ONE_MINUS_DST_ALPHA

        source or destination

        (1, 1, 1, 1)-(Ad, Ad, Ad, Ad)

        GL_SRC_ALPHA_SATURATE

        source

        (f, f, f, 1); f=min(As, 1-Ad)

        GL_CONSTANT_COLOR

        source or destination

        ( Rc, Gc, Bc, Ac )

        GL_CONSTANT_ALPHA

        source or destination

        ( Ac, Ac, Ac, Ac )

        If you are using one of the GL*CONSTANT* blending functions, you need to use glBlendColor() to specify the constant colors.

        void glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha );
        Sets the current red, green, blue and alpha values for use as the constant color ( Rc, Gc, Bc, Ac ) in blending operations.

        Example: When we draw polygonal surfaces, the most common choices for the source and destination factors are GL_SRC_ALPHA and ONE_MINUS_SRC_ALPHA respectively.
        Consider initially,

          color buffer = ( Rc, Gc, Bc, 1 ) = ( 0.2, 0.4, 0.4, 1 )

          color of polygon to be blended = ( Rs, Gs, Bs, As ) = ( 0.6, 0.6, 0.8, 0.5 );

        Class exercise: What will be the resulted rendered destination color D?

        Answer:

          D = ( AsRs + ( 1 - As)Rc,   AsGs + ( 1 - As)Gc,  
                AsBs + ( 1 - As)Bc,   As2 + ( 1 - As)Ac )
            = ( Rd, Gd, Bd, Ad ) = ...

        void glBlendEquation( GLenum mode );
        Specifies how framebuffer and source colors are blended together.
        GL_FUNC_ADD ( default ), GL_FUNC_SUBTRACT, GL_FUNC_REVERSE_SUBTRACT, GL_MIN, GL_MAX

    6. A Blending Example

      /*
       *  alpha.cpp
       *  This program draws several overlapping filled polygons
       *  to demonstrate the effect order has on alpha blending results.
       *  Use the 't' key to toggle the order of drawing polygons.
       */
      #include <GL/glut.h>
      #include <stdlib.h>
      
      static int leftFirst = GL_TRUE;
      
      /*  Initialize alpha blending function.
       */
      static void init(void)
      {
         glEnable (GL_BLEND);
         glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
         glShadeModel (GL_FLAT);
         glClearColor (0.0, 0.0, 0.0, 0.0);
      }
      
      static void drawLeftTriangle(void)
      {
         /* draw yellow triangle on LHS of screen */
      
         glBegin (GL_TRIANGLES);
            glColor4f(1.0, 1.0, 0.0, 0.75);
            glVertex3f(0.1, 0.9, 0.0); 
            glVertex3f(0.1, 0.1, 0.0); 
            glVertex3f(0.7, 0.5, 0.0); 
         glEnd();
      }
      
      static void drawRightTriangle(void)
      {
         /* draw cyan triangle on RHS of screen */
      
         glBegin (GL_TRIANGLES);
            glColor4f(0.0, 1.0, 1.0, 0.75);
            glVertex3f(0.9, 0.9, 0.0); 
            glVertex3f(0.3, 0.5, 0.0); 
            glVertex3f(0.9, 0.1, 0.0); 
         glEnd();
      }
      
      void display(void)
      {
         glClear(GL_COLOR_BUFFER_BIT);
      
         if (leftFirst) {
            drawLeftTriangle();
            drawRightTriangle();
         }
         else {
            drawRightTriangle();
            drawLeftTriangle();
         }
      
         glFlush();
      }
      
      void reshape(int w, int h)
      {
         glViewport(0, 0, (GLsizei) w, (GLsizei) h);
         glMatrixMode(GL_PROJECTION);
         glLoadIdentity();
         if (w <= h) 
            gluOrtho2D (0.0, 1.0, 0.0, 1.0*(GLfloat)h/(GLfloat)w);
         else 
            gluOrtho2D (0.0, 1.0*(GLfloat)w/(GLfloat)h, 0.0, 1.0);
      }
      
      void keyboard(unsigned char key, int x, int y)
      {
         switch (key) {
            case 't':
            case 'T':
               leftFirst = !leftFirst;
               glutPostRedisplay();	
               break;
            case 27:  /*  Escape key  */
               exit(0);
               break;
            default:
               break;
         }
      }
      
      /*  Main Loop
       *  Open window with initial window size, title bar, 
       *  RGBA display mode, and handle input events.
       */
      int main(int argc, char** argv)
      {
         glutInit(&argc, argv);
         glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
         glutInitWindowSize (200, 200);
         glutCreateWindow (argv[0]);
         init();
         glutReshapeFunc (reshape);
         glutKeyboardFunc (keyboard);
         glutDisplayFunc (display);
         glutMainLoop();
         return 0;
      }
      	





      Draw yellow triangle first.




      Draw blue triangle first.

      blending factors are 0.75 ( source ) and 1 - 0.75 = 0.25 ( destination ),
      because blending factor of source is larger, it has more effect on the final color than do the destination color

    7. Three-Dimensional Blending with the Depth Buffer

      When drawing three-dimensional translucent objects, you can get different appearances depending on whether you draw the polygons from back to front or from front to back.

      To simplify rendering process, we enable depth buffering but make the depth buffer read-only ( controlled by glDepthMask() while drawing the translucent objects:

      • First draw all opaque objects, with depth buffer in normal operation,
      • Preserve the depth values by making depth buffer read-only,
      • Translucent objects are drawn only if they are in front of the opaque ones, and are blended with the opaque ones.

      /*
       *  alpha3D.c
       *  This program demonstrates how to intermix opaque and
       *  alpha blended polygons in the same scene, by using 
       *  glDepthMask.  Press the 'a' key to animate moving the 
       *  transparent object through the opaque object.  Press 
       *  the 'r' key to reset the scene.
       */
      #include <GL/glut.h>
      #include <stdlib.h>
      #include <stdio.h>
      #include <unistd.h>
      
      #define MAXZ 8.0	//maximum Z buffer value
      #define MINZ -8.0	//minimum Z 
      #define ZINC 0.4	//Z increment
      
      static float solidZ = MAXZ;
      static float transparentZ = MINZ;
      static GLuint sphereList, cubeList;
      
      static void init(void)
      {
         GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 0.15 };
         GLfloat mat_shininess[] = { 100.0 };
         GLfloat position[] = { 0.5, 0.5, 1.0, 0.0 };
      
         glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
         glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
         glLightfv(GL_LIGHT0, GL_POSITION, position);
      
         glEnable(GL_LIGHTING);
         glEnable(GL_LIGHT0);
         glEnable(GL_DEPTH_TEST);
      
         sphereList = glGenLists(1);
         glNewList(sphereList, GL_COMPILE);
            glutSolidSphere (0.4, 80, 80);
         glEndList();
      
         cubeList = glGenLists(1);
         glNewList(cubeList, GL_COMPILE);
            glutSolidCube (0.6);
         glEndList();
      }
      
      void display(void)
      {
         GLfloat mat_solid[] = { 0.75, 0.75, 0.0, 1.0 };
         GLfloat mat_zero[] = { 0.0, 0.0, 0.0, 1.0 };
         GLfloat mat_transparent[] = { 0.0, 0.8, 0.8, 0.6 };
         GLfloat mat_emission[] = { 0.0, 0.3, 0.3, 0.6 };
      
         glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      
         glPushMatrix ();
            glTranslatef (-0.15, -0.15, solidZ);
            glMaterialfv(GL_FRONT, GL_EMISSION, mat_zero);
            glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_solid);
            glCallList (sphereList);
         glPopMatrix ();
      
         glPushMatrix ();
            glTranslatef (0.15, 0.15, transparentZ);
            glRotatef (15.0, 1.0, 1.0, 0.0);
            glRotatef (30.0, 0.0, 1.0, 0.0);
            glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission);
            glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_transparent);
            glEnable (GL_BLEND);
            glDepthMask (GL_FALSE);	//read-only
            glBlendFunc (GL_SRC_ALPHA, GL_ONE);
            glCallList (cubeList);
            glDepthMask (GL_TRUE);	//normal read-write
            glDisable (GL_BLEND);	
         glPopMatrix ();
      
         glutSwapBuffers();
      }
      
      void reshape(int w, int h)
      {
         glViewport(0, 0, (GLint) w, (GLint) h);
         glMatrixMode(GL_PROJECTION);
         glLoadIdentity();
         if (w <= h)
            glOrtho (-1.5, 1.5, -1.5*(GLfloat)h/(GLfloat)w,
               1.5*(GLfloat)h/(GLfloat)w, -10.0, 10.0);
         else
            glOrtho (-1.5*(GLfloat)w/(GLfloat)h,
               1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0);
         glMatrixMode(GL_MODELVIEW);
         glLoadIdentity();
      }
      
      void animate(void)
      {
         if (solidZ <= MINZ || transparentZ >= MAXZ)
            glutIdleFunc(NULL);  	//disable execution of animate
         else {
            solidZ -= ZINC;
            transparentZ += ZINC;
            glutPostRedisplay();
            sleep ( 2 );		//sleep 2 seconds
         }
      }
      
      void keyboard(unsigned char key, int x, int y)
      {
         switch (key) {
            case 'a':
            case 'A':
               solidZ = MAXZ;
               transparentZ = MINZ;
               glutIdleFunc(animate);	//if no other pending events, 
      				//  execute animate 
               break;
            case 'r':
            case 'R':
               solidZ = MAXZ;
               transparentZ = MINZ;
               glutPostRedisplay();
               break;
            case 27:
              exit(0);
          }
      }
      
      int main(int argc, char** argv)
      {
         glutInit(&argc, argv);
         glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
         glutInitWindowSize(500, 500);
         glutCreateWindow(argv[0]);
         init();
         glutReshapeFunc(reshape);
         glutKeyboardFunc(keyboard);
         glutDisplayFunc(display);
         glutMainLoop();
         return 0;
      }
        

       

       

    8. Antialiasing

      aliasing -- the jaggedness that appears when approximating an ideal line by a series of pixels that must lie on the pixel grid.

         

      To turn on antialiasing

      glEnable( GL_POINT_SMOOTH );
      Or
      glEnable( GL_LINE_SMOOTH );

      Use glHint() to provide a quality hint:

      void glHint(GLenum target, GLenum hint);
      Controls certain aspects of OpenGL behavior. The target parameter indicates which behavior is to be controlled; its possible values are shown in Table below. The hint parameter can be GL_FASTEST to indicate that the most efficient option should be chosen, GL_NICEST to indicate the highest-quality option, or GL_DONT_CARE to indicate no preference. The interpretation of hints is implementation-dependent; an implementation can ignore them entirely.

      Parameter

      Meaning

      GL_POINT_SMOOTH_HINT, GL_LINE_SMOOTH_HINT, GL_POLYGON_SMOOTH_HINT

      Specify the desired sampling quality of points, lines, or polygons during antialiasing operations

      GL_FOG_HINT

      Specifies whether fog calculations are done per pixel (GL_NICEST) or per vertex (GL_FASTEST)

      GL_PERSPECTIVE_CORRECTION_HINT

      Specifies the desired quality of color and texture-coordinate interpolation

      Example: Antialiased Lines

      //aargb.cpp
      #include <GL/gl.h>
      #include <GL/glu.h>
      #include <GL/glut.h>
      #include <stdlib.h>
      #include <stdio.h>
      
      static float rotAngle = 0.;
      
      /*  Initialize antialiasing for RGBA mode, including alpha
       *  blending, hint, and line width.  Print out implementation
       *  specific info on line width granularity and width.
       */
      void init(void)
      {
         GLfloat values[2];
         glGetFloatv (GL_LINE_WIDTH_GRANULARITY, values);
         printf ("GL_LINE_WIDTH_GRANULARITY value is %3.1f\n",
            values[0]);
         glGetFloatv (GL_LINE_WIDTH_RANGE, values);
         printf ("GL_LINE_WIDTH_RANGE values are %3.1f %3.1f\n",
            values[0], values[1]);
      
         glEnable (GL_LINE_SMOOTH);
         glEnable (GL_BLEND);
         glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
         glHint (GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
         glLineWidth (1.5);
      
         glClearColor(0.0, 0.0, 0.0, 0.0);
      }
      
      /* Draw 2 diagonal lines to form an X */
      void display(void)
      {
         glClear(GL_COLOR_BUFFER_BIT);
      
         glColor3f (0.0, 1.0, 0.0);
         glPushMatrix();
         glRotatef(-rotAngle, 0.0, 0.0, 0.1);
         glBegin (GL_LINES);
            glVertex2f (-0.5, 0.5);
            glVertex2f (0.5, -0.5);
         glEnd ();
         glPopMatrix();
      
         glColor3f (0.0, 0.0, 1.0);
         glPushMatrix();
         glRotatef(rotAngle, 0.0, 0.0, 0.1);
         glBegin (GL_LINES);
            glVertex2f (0.5, 0.5);
            glVertex2f (-0.5, -0.5);
         glEnd ();
         glPopMatrix();
      
         glFlush();
      }
      void reshape(int w, int h)
      {
         glViewport(0, 0, (GLint) w, (GLint) h);
         glMatrixMode(GL_PROJECTION);
         glLoadIdentity();
         if (w <= h) 
            gluOrtho2D (-1.0, 1.0, 
               -1.0*(GLfloat)h/(GLfloat)w, 1.0*(GLfloat)h/(GLfloat)w);
         else 
            gluOrtho2D (-1.0*(GLfloat)w/(GLfloat)h, 
               1.0*(GLfloat)w/(GLfloat)h, -1.0, 1.0);
         glMatrixMode(GL_MODELVIEW);
         glLoadIdentity();
      }
      
      void keyboard(unsigned char key, int x, int y)
      {
         switch (key) {
            case `r':
            case `R':
               rotAngle += 20.;
               if (rotAngle >= 360.) rotAngle = 0.;
               glutPostRedisplay();   
               break;
            case 27:  /*  Escape Key  */
               exit(0);
               break;
            default:
               break;
          }
      }
      
      int main(int argc, char** argv)
      {
         glutInit(&argc, argv);
         glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
         glutInitWindowSize (200, 200);
         glutCreateWindow (argv[0]);
         init();
         glutReshapeFunc (reshape);
         glutKeyboardFunc (keyboard);
         glutDisplayFunc (display);
         glutMainLoop();
         return 0;
      }
      

    9. Fog

      You can use fog to make an entire image appear more natural by adding fog, which makes object fade into the distance.

      Using the fog effect on points and lines is also called depth-cuing.

      Enabled by

      glEnable( GL_FOG );

      Fog blends a fog color with an object's color using a blending factor f ( in [0,1] ) computed according to:

      f = e -(density . z )   ( GL_EXP )
      f = e -(density . z )2   ( GL_EXP2 )
      f =     end - z    
      end - start
        ( GL_LINEAR )

      where z = distance between viewpoint and object

      density, end, start are input parameters of glFog*()

      If Cf = color of fog, Ci = color of object, the final blended color is given by

      C = fCi + ( 1 - f )Cf

      void glFog{if}(GLenum pname, TYPE param);
      void glFog{if}v(GLenum pname, TYPE *params);
      Sets the parameters and function for calculating fog. If pname is GL_FOG_MODE, then param is either GL_EXP (the default), GL_EXP2, or GL_LINEAR to select one of the three fog factors. If pname is GL_FOG_DENSITY, GL_FOG_START, or GL_FOG_END, then param is (or points to, with the vector version of the command) a value for density, start, or end in the equations. (The default values are 1, 0, and 1, respectively.) In RGBA mode, pname can be GL_FOG_COLOR, in which case params points to four values that specify the fog's RGBA color values. The corresponding value for pname in color-index mode is GL_FOG_INDEX, for which param is a single value specifying the fog's color index.

      Example: Five fogged spheres

      //fog.cpp
      #include <GL/gl.h>
      #include <GL/glu.h>
      #include <math.h>
      #include <GL/glut.h>
      #include <stdlib.h>
      #include <stdio.h>
      
      static GLint fogMode;
      
      static void init(void)
      {
         GLfloat position[] = { 0.5, 0.5, 3.0, 0.0 };
      
         glEnable(GL_DEPTH_TEST);
      
         glLightfv(GL_LIGHT0, GL_POSITION, position);
         glEnable(GL_LIGHTING);
         glEnable(GL_LIGHT0);
         {
            GLfloat mat[3] = {0.1745, 0.01175, 0.01175};      
            glMaterialfv (GL_FRONT, GL_AMBIENT, mat);
            mat[0] = 0.61424; mat[1] = 0.04136; mat[2] = 0.04136;     
            glMaterialfv (GL_FRONT, GL_DIFFUSE, mat);
            mat[0] = 0.727811; mat[1] = 0.626959; mat[2] = 0.626959;
            glMaterialfv (GL_FRONT, GL_SPECULAR, mat);
            glMaterialf (GL_FRONT, GL_SHININESS, 0.6*128.0);
         }
      
         glEnable(GL_FOG);
         {
            GLfloat fogColor[4] = {0.5, 0.5, 0.5, 1.0};
      
            fogMode = GL_EXP;
            glFogi (GL_FOG_MODE, fogMode);
            glFogfv (GL_FOG_COLOR, fogColor);
            glFogf (GL_FOG_DENSITY, 0.35);
            glHint (GL_FOG_HINT, GL_DONT_CARE);
            glFogf (GL_FOG_START, 1.0);
            glFogf (GL_FOG_END, 5.0);
         }
         glClearColor(0.5, 0.5, 0.5, 1.0);  /* fog color */
      }
      
      static void renderSphere (GLfloat x, GLfloat y, GLfloat z)
      {
         glPushMatrix();
         glTranslatef (x, y, z);
         glutSolidSphere(0.4, 60, 60);
         glPopMatrix();
      }
      
      /* display() draws 5 spheres at different z positions.
       */
      void display(void)
      {
         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
         renderSphere (-2., -0.5, -1.0);
         renderSphere (-1., -0.5, -2.0);
         renderSphere (0., -0.5, -3.0);
         renderSphere (1., -0.5, -4.0);
         renderSphere (2., -0.5, -5.0);
         glFlush();
      }
      
      void reshape(int w, int h)
      {
         glViewport(0, 0, (GLsizei) w, (GLsizei) h);
         glMatrixMode(GL_PROJECTION);
         glLoadIdentity();
         if (w <= h)
            glOrtho (-2.5, 2.5, -2.5*(GLfloat)h/(GLfloat)w,
               2.5*(GLfloat)h/(GLfloat)w, -10.0, 10.0);
         else
            glOrtho (-2.5*(GLfloat)w/(GLfloat)h,
               2.5*(GLfloat)w/(GLfloat)h, -2.5, 2.5, -10.0, 10.0);
         glMatrixMode(GL_MODELVIEW);
         glLoadIdentity ();
      }
      
      void keyboard(unsigned char key, int x, int y)
      {
         switch (key) {
            case `f':
            case `F':
               if (fogMode == GL_EXP) {
                  fogMode = GL_EXP2;
                  printf ("Fog mode is GL_EXP2\n");
               }
               else if (fogMode == GL_EXP2) {
                  fogMode = GL_LINEAR;
                  printf ("Fog mode is GL_LINEAR\n");
               }
               else if (fogMode == GL_LINEAR) {
                  fogMode = GL_EXP;
                  printf ("Fog mode is GL_EXP\n");
               }
               glFogi (GL_FOG_MODE, fogMode);
               glutPostRedisplay();
               break;
            case 27:
               exit(0);
               break;
            default:
               break;
         }
      }
      
      int main(int argc, char** argv)
      {
         glutInit(&argc, argv);
         glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
         glutInitWindowSize(500, 500);
         glutCreateWindow(argv[0]);
         init();
         glutReshapeFunc (reshape);
         glutKeyboardFunc (keyboard);
         glutDisplayFunc (display);
         glutMainLoop();
         return 0;
      }
      

      GL_EXP
      GL_EXP2
      GL_LINEAR