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 #include #include 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?

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

• 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π

• 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

• partition 1 into ( 1 - t ) and t

• 1 = 12 = ( ( 1 - t ) + t ) 2 = ( 1 - t ) 2 + 2 ( 1 - t ) t + t2

• We can form an affine combination of points A, B, C : P(t) = ( 1 - t) 2A + 2 t ( 1 - t ) B + t2 C P(t) is a valid point. ( Why ? )

• P(t) is a quadratic function of t, representing a curve called Bezier Curve

• Similarly, we form a cubic curve from 4 points A, B, C, D with coefficients

1 = ( ( 1 - t ) + t ) 3 = ( 1 - t ) 3 + 3 ( 1 - t ) 2 t + 3 ( 1 - t ) t 2 + t3 or

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

M = T =
 1 0 0 Tx 0 1 0 Ty 0 0 1 Tz 0 0 0 1

 void glTranslate{fd}(TYPE Tx, TYPE Ty, TYPE Tz); Multiplies the current matrix by a matrix that moves (translates) an object by the given Tx, Ty, and Tz values (or moves the local coordinate system by the same amounts).

Scaling

M = S =
 Sx 0 0 0 0 Sy 0 0 0 0 Sz 0 0 0 0 1

Scaling and reflection: glScalef(2.0, -0.5, 1.0);

 void glScale{fd}(TYPE Sx, TYPE Sy, TYPE Sz); Multiplies the current matrix by a matrix that stretches, shrinks, or reflects an object along the axes. Each x, y, and z coordinate of every point in the object is multiplied by the corresponding argument Sx, Sy, or Sz. With the local coordinate system approach, the local coordinate axes are stretched, shrunk, or reflected by the Sx, Sy, and Sz factors, and the associated object is transformed with them.

Rotations

Rotation about an axis

Elementary rotations about a coordinate axis:

• z-roll -- rotation about z-axis ( x-axis rotates to y-axis )
• y-roll -- rotation about y-axis ( z-axis rotates to x-axis )
• x-roll -- rotation about x-axis ( y-axis rotates to z-axis )
• Suppose

θ = angle of rotation

A z-roll:
Rz ( θ ) =
 cos θ -sin θ 0 0 sin θ cos θ 0 0 0 0 1 0 0 0 0 1
A y-roll:
Ry ( θ ) =
 cos θ 0 sin θ 0 0 1 0 0 -sin θ 0 cos θ 0 0 0 0 1
An x-roll:
Rx ( θ ) =
 1 0 0 0 0 cos θ -sin θ 0 0 sin θ cos θ 0 0 0 0 1

Example: Where will be the point P = ( 3, 1, 4 ) after a rotation of 30o about the y-axis.

Solution:
----------
Here θ = 30o, cos θ = 0.866, and sin θ = 0.5 The new position is given by
Q = M.P = Ry(30o).P =
 0.866 0 0.5 0 0 1 0 0 -0.5 0 0.866 0 0 0 0 1
3
1
4
1
=   4.6
1
1.964
1
As expected, the y-coordinate of the point is not altered.
----------

3D affine transformations can be composed and the result is another 3D affine transformation

M = M2M1       ( M2 follows M1 ) Note: M2M1 ≠ M1M2 It is very common to build a rotation in 3D by composing three elementary rotations: an x-roll followed by y-roll and then a z-roll. M = Rz3) Ry2) Rx1)

Example: What is the matrix associated with an x-roll of 45o, followed by a y-roll of 30o, followed by a z-roll of 60o,

Solution:

 Euler's Theorem: Any rotation ( or sequence of rotations ) about a point is equivalent to a single rotation about some axis through that point.
 void glRotate{fd}(TYPE angle, TYPE x, TYPE y, TYPE z); Multiplies the current matrix by a matrix that rotates an object (or the local coordinate system) in a counterclockwise direction about the ray from the origin through the point (x, y, z). The angle parameter specifies the angle of rotation in degrees.

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

```	glLoadIdentity();	//M = I
glTranslatef();		//M = I.T = T
glRotate();		//M = M.R = T.R
glScale();		//M = M.S = T.R.S
draw_a_point( P );	//Q = M.P = T.R.S.P
```

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?

 ``` glTranslatef ( 1.0, 0.0, 0.0 ); glRotatef( degrees, 0.0, 0.0, 1.0 ); glTranslatef ( -1.0, 0.0, 0.0 ); draw_object(); ```

Or  ``` glTranslatef ( -1.0, 0.0, 0.0 ); glRotatef( degrees, 0.0, 0.0, 1.0 ); glTranslatef ( 1.0, 0.0, 0.0 ); draw_object(); ```

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 #include 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: