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

    Viewing I -- Affine Transformations

    1. Pipeline Architecture

      A series of three computer operations convert an object's three-dimensional coordinates to pixel positions on the screen.

    2. Transformations :
        Represented by matrix multiplication, include modeling, viewing, and projection operations. e.g. rotation, translation, scaling, reflecting, orthographic projection, and perspective projection.

    3. Clipping :
        Since the scene is rendered on a rectangular window, objects (or parts of objects) that lie outside the window must be clipped.

    4. Viewport mapping:
        A correspondence must be established between the transformed coordinates and screen pixels.
    5. We use a 4 x 4 matrix M to specify viewing, modeling or projection transformations.

      v' = M v

    6. A Simple Example: Transformed Cube

      //cube.cpp
      #include <GL/gl.h>
      #include <GL/glu.h>
      #include <GL/glut.h>
      
      void init(void) 
      {
         glClearColor (0.0, 0.0, 0.0, 0.0);
         glShadeModel (GL_FLAT);
      }
      
      void display(void)
      {
         glClear (GL_COLOR_BUFFER_BIT);
         glColor3f (1.0, 1.0, 1.0);
         glLoadIdentity ();             /* clear the matrix */
                 /* viewing transformation  */
         gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
         glScalef (1.0, 2.0, 1.0);      /* modeling transformation */ 
         glutWireCube (1.0);
         glFlush ();
      }
      
      void reshape (int w, int h)
      {
         glViewport (0, 0, (GLsizei) w, (GLsizei) h); 
         glMatrixMode (GL_PROJECTION);
         glLoadIdentity ();
         glFrustum (-1.0, 1.0, -1.0, 1.0, 1.5, 20.0);
         glMatrixMode (GL_MODELVIEW);
      }
      
      int main(int argc, char** argv)
      {
         glutInit(&argc, argv);
         glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
         glutInitWindowSize (500, 500); 
         glutInitWindowPosition (100, 100);
         glutCreateWindow (argv[0]);
         init ();
         glutDisplayFunc(display); 
         glutReshapeFunc(reshape);
         glutMainLoop();
         return 0;
      }
      

      gluLookAt() specifies where the camera ( eye position ) is placed. By default, the camera is located at the origin, pointing down the negative z-axis.

      gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);:

      • camera at ( 0, 0, 5 )
      • aim camera lens towards ( 0, 0, 0 )
      • orientation of camera is specified by up-vector ( 0, 1, 0 ) ( So, in this example, y-axis is the up-down axis; right-hand rule is used: consequently, x-axis is left-right axis.
        If up-vector were ( 1, 0, 0 ), then +x points upward and +y points left. )

      glFrustum() -- defines the projection transformation (
      a more commonly used alternative routine is gluPerspective() )

    7. Orthogonal Matrices

    8. Orthogonality: An invertible n x n matrix M is called orthogonal if and only if M-1 = MT.

      Theorem. If the vectors V1,V2, ..., Vn form an orthonormal set, then the n x n matrix M constructed by setting the j-th column equal to Vj for all 1 ≤ j ≤ n is orthogonal.

      Proof. Since Vj's are orthonormal, ( MTM ) ij = Vi.Vj = dij where dij is the Kronecker delta symbol. So MT M = I. Therefore, MT = M -1 .

    9. Length and Angle Preservation:
      • A matrix M preseves length if for any vector P we have |M P| = |P|

      • A matrix that preserves lengths also preserves angles if for any two vectors P and Q, we have ( M P ).( MQ ) = P . Q

      Theorem. If the n x n matrix M is orthogonal, then M preserves lengths and angles.

      Proof. Let M be orthogonal and P, Q are two vectors. Then

        ( M P ).( M Q )     ( vector dot product )
        = ( MP )T ( M Q )
        = PT M T M Q
        = PT Q
        = P . Q
      This implies that the matrix preserves angles. It also implies that the length of vector P is preserved when transformed by matrix M since |P|2 = P.P

      Example

        M =  
        1
        0
        0
        0
            0
        1
        0
        0
            0
        0
        -1
        0
            0
        0
        0
        1
           
      Rotations, reflections, and their combinations produce orthogonal matrices.
    10. Homogeneous Coordinates

      Vectors and Points

    11. a vector v = ( 3, 2, 7 )

    12. a point P = ( 5, 3, 1 )

    13. They look the same but actually vectors and points are very different: a point has a location, but no size or direction, whereas a vector has a size and direction but no location

    14. The difference between two points is a vector

    15. Problem arises when one transforms points or vectors from one system into another

    16. It is useful to represent both points and vectors using the same set of basic underlying objects
    17. Homogeneous Representation of a Point and a Vector

      A vector

        v = ( vx, vy, vz, 0 )

      A point

        P = ( Px, Py, Pz, 1 )

      Properties

      • The difference of two points is a vector. Why?

      • The sum of a point and a vector is a          

      • The difference or sum of two vectors is          

      • It is meaningful to sacle a vector: 3(x, y, z, 0 ) = ( 3x, 3y, 3z, 0 )

      • It is meaningful to form any linear combination of vectors: v = ( vx, vy, vz, 0 )
        u = ( ux, uy, uz, 0 )
        av + bu = ( avx + bux, avy + buy, avz + buz, 0 )
        which is a valid vector

      • What is the sum of two points? Does it make sense to form a linear combination of points?

    18. Affine Combinations of Points

      Consider a linear combination of two points P = ( Px, Py, Pz, 1 ), Q = ( Qx, Qy, Qz, 1 ),
        cP + dQ = ( cPx + dQx, cPy + dQy, cPz + dQz, c + d )

    19. It is a valid vector if c + d = 0 ( why? )

    20. It a valid point only if c + d = 1

    21. Affine combination -- sum of the coefficients of a linear combination is 1
      Examples:
        0.3P + 0.7Q is a valid point
        2.7P - 1.7Q is a valid point
        P + Q is not a point
        0.3P + 0.9Q - 0.2R is a valid point
        P + Q - 0.8R is not valid

      Any affine combination of points is a legitimate point

    22. A point plus a vector is an affine combination of points
        Suppose P = Q + tv

        Let

        v = R - Q

        Then

        P = Q + t ( R - Q )

        or

        P = tR + ( 1-t )Q

        which is a valid point as t + (1-t) is 1. So a point plus a scaled vector is also a valid point.

    23. Point or vector ?
        Consider the general situation of forming a linear combination of m points

        Is A a point or a vector?

        Answer:

        Calculate the sum of coefficients

        1. A is a point if S = 1
        2. A is a vector if S = 0
        3. A is meaningless for other values of S

    24. Example: The Centroid of a triangle

      We use the preceeding ideas to show that the three medians of the above triangle meet at a point that lies two-thirds of the way along each median. This point is the centroid. Proof:

        By definition, the median from A is the line from A to the midpoint of the opposite side. Thus

          D = ( B + C ) / 2

        The point that is two-thirds of the way from A to D lies at

          G = A + t ( D - A )     with t = 2 / 3

        which yields

        Since this result is symmetrical in A, B and C, it must also be two-thirds of the way along the median from B and two-thirds of the way along the median from C. Hence the three medians meet there, and G is the centroid.

        This result generalizes nicely for a regular polygon with N sides: the centroid is simply the average of the location of the N vertices, another affine combination

    25. Linear Interpolation of two points

      Linear interpolation between points R and Q:

        P = ( 1 - t ) Q + t R

      In one dimension, it can be implemented as:

        	float lerp ( float q, float r, float t ) 
        	{
        	  return q + ( r - q ) * t;	//same as ( 1 - t ) * q + t * r;
        	}
        	

      Point P(t) is tween ( in-between ) at t of points Q and R if t is a fraction and P(t) is computed the way along the straight line QR.

        	Point2 tween( Point2 P1, Point2 P2, float t )
        	{
          	  Point2 P;
          	  P.x = P1.x + ( P2.x - P1.x ) * t;
          	  P.y = P1.y + ( P2.y - P1.y ) * t;
          	  return P;
        	}
        	
    26. Parametric Form for a Curve ( 2D )

      implicit form:

        F( x, y ) = 0

      e.g. Straight line through points P and Q:

        F(x, y) = ( y - Py )( Qx - Px ) - ( x - Px )( Qy - Py )

      e.g Circle with radius R centered at origin:

        F(x, y ) = x2 + y2 - R2

      Advantages:

      • easily test if a point lies on curve
      • meaningful to speak of inside, outside curve F(x, y) = 0     ( x, y ) on curve

        F(x, y) > 0     ( x, y ) outside curve

        F(x, y) < 0     ( x, y ) inside curve

      parametric Form:

      • based on the value of a parmeter
      • path of a particle travelling along the curve is ( x(t), y(t) )

      e.g. A line passing through points P at t = 0, and Q at t = 1

        x(t) = Px + ( Qx - Px )t

        y(t) = Py + ( Qy - Py )t

      e.g. ellipse with half width W, half height H

        x(t) = W cos ( t )

        y(t) = H sin ( t )     for 0 ≤ t ≤ 2π

      Advantages:

      • more convenient to draw or analyze
      • suggests the movement of a point over time
      • can be drawn by:
        		//draw the curve ( x(t), y(t) ) using 
        		//  the array t[0] .... t[n-1] of "sample-times"
        		glBegin( GL_LINES )
        		  for ( int i = 0; i < n; ++i )
        		    glVertex2f( x(t[i]), y(t[i]) );
        		glEnd();
        	  
      • 3D curves:

        P(t) = ( x(t), y(t), z(t) )

        e.g circular helix

        x(t) = cos ( t )

        y(t) = sin ( t )

        z(t) = bt

    27. Quadratic and Cubic Tweening

    28. 3D Affine Transformations

      affinis ~ connected with
      In general, an affine transformation is composed of linear transformations (rotation, scaling or shear) and
      a translation (or "shift"):

      P' = AP + D

      Geometrically, an affine transformation in Euclidean space is one that preserves:

      1. The collinearity relation between points; i.e., the points which lie on
        a line continue to be collinear after the transformation.
      2. Ratios of distances along a line; i.e., for distinct collinear points
        p1,p2,p3, the ratio | p2 - p1 | / | p3 - p2 | is preserved.


      An image of a fern that exhibits affine self-similarity

      Consider two points P and Q

      P =  
      Px
      Py
      Pz
      1
             
      Q =  
      Qx
      Qy
      Qz
      1

      An affine transformation can transform point P to point Q and the transformation can be represented by a matrix M

      M =  
      m11   m12   m13   m14  
      m21   m22   m23   m24  
      m31   m32   m33   m34  
      0 0 0 1

      Q can be found by

      Qx
      Qy
      Qz
      1
        =  
      m11   m12   m13   m14  
      m21   m22   m23   m24  
      m31   m32   m33   m34  
      0 0 0 1
      Px
      Py
      Pz
      1

      If mii = 1 and mij = 0 for i ≠ j, we have the identity matrix:

      I =  
        1     0     0     0  
      0 1 0 0
      0 0 1 0
      0 0 0 1

      void glLoadIdentity( void );
      Sets the current matrix to the 4 x 4 identity matrix

      void glLoadMatrix{fd}(const TYPE *m);
      Sets the sixteen values of the current matrix to those specified by m.

      void glMultMatrix{fd}(const TYPE *m);
      Multiplies the matrix specified by the sixteen values pointed to by m by the current matrix and stores the result as the current matrix.

      void glPushMatrix( void );
      'Pushes current Matrix' onto stack. The current stack is determined by glMatrixMode().

      void glPopMatrix( void );
      'Pops matrix at top of stack' onto current stack. The current stack is determined by glMatrixMode().

      Translation

      Scaling

      Rotations

      Rotation about an axis

    29. An Affine ( Modeling ) Transformation Code Example

      glLoadIdentity();
      glColor3f(1.0, 1.0, 1.0);
      draw_triangle();                   /* solid lines */
      
      glEnable(GL_LINE_STIPPLE);         /* dashed lines */
      glLineStipple(1, 0xF0F0); 
      glLoadIdentity();
      glTranslatef(-20.0, 0.0, 0.0);
      draw_triangle();
      
      glLineStipple(1, 0xF00F);          /*long dashed lines */
      glLoadIdentity();
      glScalef(1.5, 0.5, 1.0);
      draw_triangle();
      
      glLineStipple(1, 0x8888);          /* dotted lines */
      glLoadIdentity();
      glRotatef (90.0, 0.0, 0.0, 1.0);
      draw_triangle ();
      glDisable (GL_LINE_STIPPLE);
        
      void draw_trangle( void )
      {
         glBegin ( GL_LINE_LOOP );
           glVertex2f( 0.0, 25.0 );
           glVertex2f( 25.0, -25.0 );
           glVertex2f( -25.0, -25.0 );
         glEnd();
      }
        


        Mesh msh;
        msh.readFile( DATA_FILE );
        msh.drawMesh();
        glFlush();
        SDL_Delay ( 1000 );
        glPushMatrix();               //save current matrix M
        glTranslatef ( 2.0, 0, 0 );   //move in x-direction
        msh.drawMesh();
        glFlush();
        SDL_Delay ( 1000 );
        glRotatef ( 90, 0, 1, 0 );    //rotate about  y-axis for 90
        msh.drawMesh();               //? "translate then rotate" or "rotate translate" ?
        glFlush();
        SDL_Delay ( 1000 );
        glPopMatrix();                //restore maxtrix M
        glRotatef ( 90, 0, 1, 0 );
        glTranslatef ( 2.0, 0, 0 );   //? "translate rotate" or "rotate translate" ?
        msh.drawMesh();
        glFlush();
        
       

    30. Some Useful and Pleasing Properties of Affine Transformations

    31. Affine Transformations Preserve Affine Combination of Points

      Suppose C is an affine combination of two points A and B:

        C = aA + bB     where a + b = 1
      Under affine transformation with matrix M,
        M.C = M(aA + bB) = a(M.A) + b(M.B)

    32. Lines and planes are preserved

      i.e. lines remain lines, planes remain plane after transform

      A straight line passing through points A, B is:

        L(t) = (1-t)A + tB

      The image of L(t) is the same affine combination of the images of A and B:

        L'(t) = (1-t)M.A + tM.B

      A plane can be written as an affine combination of 3 points, A, B, and C:

        P(s,t) = sA + tB + (1 - s - t)C
      When each point is transformed, this becomes:
        M.P(s,t) = sM.A + tM.B + (1 - s - t)M.C

    33. Parallelism of Lines and Planes is Preserved

      Consider two lines with same direction b:

        L1(t) = A + bt

        L2(t) = B + bt

      Under affine transformation M, they become

        L'1(t) = M.A + (Mb)t

        L'2(t) = M.B + (Mb)t

      The transformed lines have the same direction (Mb).

      Two planes with same directional normal can be described by

        P1(s,t) = A + as + bt

        P2(s,t) = B + as + bt

      Under affine transformation

        P'1(t) = M.A + (Ma)s + (Mb)t

        P'2(t) = M.B + (Ma)s + (Mb)t

    34. Proportional distances are preserved
        e.g. if point P is between points A and B, and PA/PB = r before, the ratio r will remain so after the transform
    35. Volume of enclosed objects:

        ( volume after transformation ) / ( volume before ) = | det M |
    36. Examples of Composing Several Transformations

      Note again: M2M1 ≠ M1M2

      Note that the equivalent order of operation on P is : scale, rotate, translate

      Suppose we want to rotate an object about a 'z' axis through ( -1, 0, 0 ). We can achieve this by moving everything by 1, do the rotation, and move things back by 1.

      Question: Which of the following is correct?

      Example: Building an Articulated Robot Arm

    37. Scale a cube as a segment of the robot arm
    38. Call the appropriate modeling transformations to orient each segment
    39. As a rotating axis always passes through origin ( 0, 0, 0 ), if we want to rotate an object about another axis (e.g. an axis passing through a cube edge), we first move the local coordinate system ( object ) to one edge of the cube ( pivot point for rotating ) using glTranslatef(); after rotation, we move the system ( object ) back with glTranslatef():

      glTranslatef (-1.0, 0.0, 0.0);
      glRotatef ((GLfloat) shoulder, 0.0, 0.0, 1.0);
      glTranslatef (1.0, 0.0, 0.0);
      glPushMatrix();
      glScalef (2.0, 0.4, 1.0);
      glutWireCube (1.0);
      glPopMatrix();
      

    40. The second segment is built by moving the local system to the next pivot point:

      glTranslatef (1.0, 0.0, 0.0);	 
      glRotatef ((GLfloat) elbow, 0.0, 0.0, 1.0);
      glTranslatef (1.0, 0.0, 0.0);  
      glPushMatrix();
      glScalef (2.0, 0.4, 1.0);
      glutWireCube (1.0);
      glPopMatrix();
          

    41. The complete program:

      
      //robot.cpp
      #include <GL/glut.h>
      #include <stdlib.h>
      
      static int shoulder = 0, elbow = 0;
      
      void init(void) 
      {
         glClearColor (0.0, 0.0, 0.0, 0.0);
         glShadeModel (GL_FLAT);
      }
      
       
      /*
        glutWireCube ( 1.0 )  
        produces a cube: -0.5 to 0.5
      */
      void display(void)
      {
         glClear (GL_COLOR_BUFFER_BIT);
         glPushMatrix();				  //Save M0
         glTranslatef (-1.0, 0.0, 0.0);		  //M1 = T-1
         glRotatef ((GLfloat) shoulder, 0.0, 0.0, 1.0); //M2 = T-1Rs
         glTranslatef (1.0, 0.0, 0.0);		  //M3 = T-1RsT+1
         glPushMatrix();				  //Save M3
         glScalef (2.0, 0.4, 1.0);			  //M4 = T-1RsT+1S
         glutWireCube (1.0);				  //P' =  T-1RsT+1S P
         glPopMatrix();				  //Restore M3 = T-1RsT+1
         glTranslatef (1.0, 0.0, 0.0);		  //M5 = T-1RsT+1T+1
         glRotatef ((GLfloat) elbow, 0.0, 0.0, 1.0);	  //M6 = T-1RsT+1T+1Re
         glTranslatef (1.0, 0.0, 0.0);		  //M7 = T-1RsT+1T+1ReT+1
         glPushMatrix();				  //Save M7
         glScalef (2.0, 0.4, 1.0);			  //M8 = T-1RsT+1T+1ReT+1S
         glutWireCube (1.0);				  //P' = T-1RsT+1T+1ReT+1S P
         glPopMatrix();				  //Restore M7 
      
         glPopMatrix();				  //Restore M0
         glutSwapBuffers();
      }
      
      void reshape (int w, int h)
      {
         glViewport (0, 0, (GLsizei) w, (GLsizei) h); 
         glMatrixMode (GL_PROJECTION);
         glLoadIdentity ();
         gluPerspective(65.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);
         glMatrixMode(GL_MODELVIEW);
         glLoadIdentity();
         glTranslatef (0.0, 0.0, -5.0);
      }
      void keyboard (unsigned char key, int x, int y)
      {
         switch (key) {
            case 's':
               shoulder = (shoulder + 5) % 360;
               glutPostRedisplay();
               break;
            case 'S':
               shoulder = (shoulder - 5) % 360;
               glutPostRedisplay();
               break;
            case 'e':
               elbow = (elbow + 5) % 360;
               glutPostRedisplay();
               break;
            case 'E':
               elbow = (elbow - 5) % 360;
               glutPostRedisplay();
               break;
            case 27:
               exit(0);
               break;
            default:
               break;
         }
      }
      
      int main(int argc, char** argv)
      {
         glutInit(&argc, argv);
         glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
         glutInitWindowSize (500, 500); 
         glutInitWindowPosition (100, 100);
         glutCreateWindow (argv[0]);
         init ();
         glutDisplayFunc(display); 
         glutReshapeFunc(reshape);
         glutKeyboardFunc(keyboard);
         glutMainLoop();
         return 0;
      }
         

      Robot Arm with fingers: