Chapter 5 Small
Chapter 5 Small
Spring 2011
Chapter 5,
Transformations of Objects
Goals of the Chapter
•
.To develop tools for transforming one picture into another
To introduce the fundamental concepts of affine transformations, which perform combinations of •
rotations, scaling, and translations
•
.To develop functions that applies affine transformations to objects in computer programs
.To develop tools for transforming coordinate frames •
.To see how to set up a camera to render a 3D scene using OpenGL •
To learn to design scenes in the Scene Design language SDL, and to write programs that read SDL •
.files and draw the scenes they describe
INTRODUCTION TO TRANSFORMATIONS
Figure 5.1 (a) shows two versions of a simple house, drawn before and after each of its points
has been transformed. In this case the house has been scaled down in size, rotated a small
amount, and then moved up and to the right.
The overall transformation is a combination of three elementary ones: scaling, rotation, and
translation. Figure 5.1(b) shows a 3D house before and after it is similarly transformed: Each
.3D point in the house is subjected to a scaling, a rotation, and a translation by the transformation
Fig 5.1, Drawings of Objects before and after they are transformed
:Transformations are very useful in a number of situations
a. We can compose a "scene" out of a number of objects, as in Figure 5.2. The scene is
fashioned by placing a number of “instances” of arch at different places and with
different sizes, using the proper transformation for each.
b. The snowflake exhibit certain symmetries. We can design a single “motif” and then
fashion the whole shape by appropriate reflections, rotations, and transformations of the
motif.
Fig 5.4 Using a “motif” to build up a figure
c. A designer may want to view an object from different vantage points and make a picture
from each one. The scene can be rotated and viewed with same camera, but it is more
natural to leave the scene alone and move the camera.
Figure 5,7 shows a simplified view of the OpenGL graphics pipeline. An application sends the
pipeline a sequence of points P1, P2, P3,... using commands like,
glBegin (GL_LINES);
glVertex3f (...); // send PI through the pipeline
glVertex3f (...): // send P2 through the pipeline
glVertex3f (...); // send P3 through the pipeline
glEnd ():
These points first encounter a transformation called the "current transformation" (CT), which
alters their values into a different set of points, say Q1, Q2, Q3, … Just as the original points Pi
describe some geometric object, the points Qi, describe the Transformed version of the same
object. These points are then sent through additional steps and ultimately are used lo draw the
final image on the display.
Fig 5.7 The OpenGL pipeline
As the figure illustrates, an arbitrary point P in the plane is mapped to another point Q. We say
that Q is the image of P under the mapping T. More formally, if S is a set of points, its image
T(S) is the set of all points T(P) , where P is some point in S.
We take the 2D case first, in whichever coordinate frame we are using, points P and Q have the
representations
Px Qx
P = Py and Q = Qy
1 1
Affine transformations have a simple form. The coordinates of Q are linear combinations of
those of P.
Qx m11 Px + m12Py + m13
Qy = m21 Px + m12Py + m23
1 1
Example 5.2.1
An affine transformation is specified by the matrix
3 0 5
-2 1 2
0 0 1
Translation
To translate a picture into a different position on a graphics display
Qx 1 0 m13 Px
Qy = 0 1 m23 Py
1 0 0 1 1
or simply
Qx Px + m13
Qy = Py + m23
1 1
Example
If the offset vector is (2, 3), every point will be altered into a new point that is two units farther to
right and three units above. The point (1, -5), for instance, is transformed into (3, -2), and the
point (0, 0) is translated into (2, 3).
Scaling
Scaling changes the size of a picture and involves two scale factors, Sx, Sy, for the x- and y-
coordinates.
(Qx, Qy) = (SxPx, SyPy).
The matrix is
Sx 0 0
0 Sy 0
0 0 1
This is called scaling about the origin, because each point P is moved Sx times farther from the
origin in the x-direction and Sy times farther from the origin in the y-direction.
There are “pure” reflections, for which each of the scale factors is +1 or –1.
If the two factors are the same (Sx = Sy = S) , is a uniform scaling. If S is negative, there are
reflection about both axes.
Rotation
A fundamental graphics operation is the rotation of a
figure about a given point through some angle, as in Fig.
o
Fig 5.13 Rotation of points through an angle of 60
As When T() is a rotation about the origin, the offset vector d is zero and Q = T(P) the form
In terms of its matrix form, a pure rotation about the origin is given by
Qx cos(q) -sin(q) 0 Px
Qy = sin(q) cos(q) 0 Py
1 0 0 1 1
P = (Rcos(f), Rsin(f)).
and
sin(q+f) = sin(q)cos(f) + cos(q)sin(f)
and use
Px = Rcos(q+f) and Py = Rsin(q+f) to obtain eq. 5.9.
Fig 5.14, Derivation of the Rotation mapping
1 0 0
g 1 0
0 0 1
If point P is mapped into point Q according to Q = MP, we simply pre-multiply both sides by
-1
the inverse of M denoted by M , and write
m22 -m12
-1
M = 1 .
det M -m21 m11
2. Rotation
cos(q) sin(q) 0
-sin(q) cos(q) 0
-1
M =
0 0 1
3. Shearing
1 -h 0
-1
M = 0 1 0
0 0 1
4. Translations
1 0 -m13
-1
M = 0 1 -m23
0 0 1
5.2.5 Composing Affine Transformations
An application requires that we build a compound transformation out of several elementary ones.
For example, we may want to
• Translate by (3, -4),
• Then rotate through 30o.
• Then scale by (2, -1).
• Then translate by (0, 15).
• And, finally, rotate through –30o.
The process of applying several transformations in succession to form one overall transformation
is called composing the transformations. Fig 5.16 T1() maps P into Q, and T2() maps Q into W.
The nature of W = T2(Q)=T2(T1(P))
Suppose the two transformations are represented by the matrices M1 and M2. P is transformed to
the point M1P, which is then transformed to M2(M1P). So, the later just (M2M1)P, and we have
W = MP.
Where M = M2M1.
Notice that the matrices appear in reverse order.
Fig 5.16 The composition of two transformations.
Creating a matrix for each elementary transformation and multiplying the matrices out produces
1 0 Vx cos(q) -sin(q) 0 1 0 -Vx cos(q) -sin(q) dx
0 1 Vy sin(q) cos(q) 0 0 1 -Vy = sin(q) cos(q) dy
0 0 1 0 0 1 0 0 1 cos(q) 0 1
where
dx = -cos(q)Vx + sin(q)Vy + Vx
dy = -sin(q)Vx - cos(q)Vy + Vy
Example 5.2.6
Scaling and shearing about arbitrary “pivot” point
We do the same “shift-transform-unshift”.
cos(2b) sin(2b) 0
sin(2b) - cos(2b) 0 (a reflection about the axis at angle b
0 0 1
Px
P = Py .
Pz
1
Qx Px
Q y = M Py
Qz Pz
1 1
5.3.1 The Elementary 3D Transformations
Translation
For pure translation, the matrix is
1 0 0 m14
0 1 0 m24
0 0 1 m34
0 0 0 1
Scaling
The matrix is
Sx 0 0 0
0 Sy 0 0
0 0 Sz 0
0 0 0 1
Shearing
The matrix for the simplest elementary shear is the identity matrix with one zero term replaced
by some value, as in
1 0 0 0
f 1 0 0
0 0 1 0
0 0 0 1
Rotations
We often want to rotate an object or a camera in order to obtain different views. We must specify
an axis about which the rotation occurs, rather than just a single point.
The simplest rotation is a rotation about one of the coordinate axes. We call a rotation about the
x-axis an "x-roll," a rotation about the y-axis a "y-roll," and a rotation about the z-axis a "z-roll."
The rotation is through an angle b, about the given axis. We define positive angles using a
"looking inward" convention:
2. A y-roll
c 0 s 0
0 1 0 0
Ry(b) = 0 -s c 0
0 0 0 1
3. A z-roll
c -s 0 0
s c 0 0
Rz(b) = 0 0 1 0
0 0 0 1
Suppose you have a routine house () that draws house #1 in Fig 5.34. But you wish instead to
draw house #2, shown rotated through -30° and then translated through (32, 25). This is a
frequently encountered situation; An object is defined at a convenient size and position, but we
want to draw it (perhaps many times) at different sizes, orientations, and locations.
Fig 5.34 Drawing a rotated and translated house.
After drawing house #, how do we arrange matters so that house #2 is drawn instead? There are
tow ways:
The routine produces Q=MP, then apply the transformation to each point V [i] in house ().
The window-to-viewport mapping is "quietly" applied to each vertex as part of moveTo () and
lineTo(). We can have an additional transformation, the current transformation, CT. We enhance
move-To () and linsTo () so that they first quietly apply CT to the argument vertex and then apply
.the window-to-viewport mapping
As in Fig 5.35, When glVertex2d () is called with the argument V, the vertex V is first
transformed by the CT to form point Q, which is then passed through the window-to-viewport
mapping to form point S in the screen window.
Fig
5.35
The
How do we extend moveTo () and lineTo () so that they quietly carry out this additional
mapping?
If you are not using OpenGL, you must write code that actually performs the transformation.
If you are using OpenGL, the transformation is done automatically! OpenGL maintains a so-
called modelview matrix, and every vertex that is passed down the graphics pipeline is
multiplied by this matrix.
.We need only set up the modelview matrix to embody the desired transformation
OpenGL works entirely in 3D, so its modelview matrix produces 3D transformations.
The principal routines for altering the modelview matrix are glRotated(), glScaled (), and
glTranslated (), (d indicated to double). These do not set the CT directly; instead, each
postmultiplies the CT (the modelview matrix) by a particular matrix, say, M, and puts the result
back into the CT. That is, each of the routines creates a matrix M required for the new
transformation and performs the operation
CT = CT* M
The following are OpenGL routines for applying transformations in the 2D case;
Since these routines only compose a transformation with the CT, we need some way to get
started:
to initialize the CT to the identity transformation. For that purpose OpenGL provides the routine
gILoadIdentity (). And because the functions listed can be set to work on any of the matrices
that OpenGL supports, we must inform OpenGL which matrix we are altering. This is
accomplished using
gIMatrixMode (GL_MODELV1EW).
The implementation of pushCT () and popCT () is simple with OpenGL, which has routines
glPushMatrix () and glPopMatrix () to manage several different slacks of matrices as in Figure
5.44.
return 0;
}
Points lying inside the view volume are projected onto the window along lines parallel to the z-
axis, i.e. ignoring the z-components of those points, so 3D point (x1, y1, z1) projects to (x1, y1, 0).
Points lying outside the view volume are clipped off.
Fig 5.51 shows such a camera immersed in a scene. The scene consists of a block, part of which
lies outside the view volume.
Fig
5.51
A
The modelview matrix provides what we have calling the CT. It combines two effects: the
sequence of modeling transformation applied to objects and the transformation that orients and
positions the camera.
The projection matrix scales and shifts each vertex in a particular way, so that all those vertices
that lie inside the view volume will lie inside a standard cube that extends from –1 to 1 in each
dimension.
Fig 5.54 Effect of the projection matrix (for parallel projections).
The viewport matrix maps the surviving portion of the block into a “3D viewport.” The matrix
maps the standard cube into a block shape whose x and y values extend across the viewport
(screen coordinate) and whose z-component extend from 0 to 1 and retains a measure of the
depth of point.
glRotated(angle, ux , uy , uz);
Postmultiply the current matrix by a matrix that performs a rotation through angle degrees about
the axis that passes through the origin and the point (ux, uy, uz). Put the result back in the
.current matrix
The torus is determined by the inner radius inRad and outer radius outRad.
The sphere and torus are approximated by polygonal faces, and you can adjust the parameters
nSlices and nStacks to specify how many faces to use in the approximation. nSlices is the
number of subdivisions around the z-axis, and nStacks is the number of "bands" along the z-
axis, as if the shape were a stack of nStacks disks.
The functions used to render four of the Platonic solids are as follows:
• tetrahedron: glutWireTetrahedron();
• octahedron: glutWireOctahedron ();
• dodecahedron: glutWireDodecahedron ();
• icosahedron: glutWireIcosahedron ();
All of the preceding shapes are centered at the origin. We also have the following solids:
• cone: glutWireCone (GLdouble baseRad, GLdouble height, GLint nSlices, GLint nStacks)
glu Quadrics
• tapered cylinder: gluCylinder (GLUquadricObj * qobj, GLdouble baseRad, GLdouble topRad,
GLdouble
height, GLint nSlices, GLint nStacks)
The axes of the cone and tapered cylinder coincide with the z-axis. Their bases rest on the z = 0
plane and extend to z = height along the z-axis. The radius of the
cone and tapered cylinder at z = 0 is given by baseRad. The radius of the tapered cylinder at z =
height is topRad.
When topRad is 1, there is no taper, and we have the classic right circular cylinder. When
topRad is 0,the tapered cylinder is identical to the cone.
Note that drawing the tapered cylinder in OpenGL requires some extra work. To draw it, you
must;
EXAMPLE 5.6.2
A scene composed of wire-frame objects Figure 5.59 shows a scene with several objects
disposed at the corners of a unit cube, which itself has one corner at the origin.
The camera is given a view volume that extends from -2 to 2 in y. with an aspect ratio of
640/480. The near plane is at N = 0.1, the far plane at F = l00. This is accomplished using
The camera is positioned with eye = (2, 2, 2), lookAt = (0, 0, 0), and up = (0, 1, 0) (parallel lo the
y-axis), using
gluLookAt (2.0, 2.0, 2.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glutWirecube (2.)
glutWireSphere (1.0, 8, 5);
glutWireTorus (0.5, 1., 8, 10);
glutWireCone (1.0, 2., 8, 10);
glutWireTetrahedron ();
glutWireOctahedron ();
#include
<windows.h>
//suitable when
using Windows
95/98/NT
#include
<gl/Gl.h>
#include
<gl/Glu.h>
#include
<gl/glut.h>
//<<<<<<<<<<<<<<<<<<< axis >>>>>>>>>>>>>>
void axis (double length) {
// draw a z-axis, with cone at end
glPushMatrix();
glBegin (GL_LINES);
glVertex3d (0, 0, 0);
glVertex3d (0,0,length); // along the z-axis
glEnd ();
glTranslated (0, 0,length -0.2);
glutWireCone (0.04, 0.2, 12, 9);
glPopMatrix ();
}
//<<<<<<<<<<<<<<<<<< displayWire >>>>>>>>>>>>>>>
void displayWire(void) {
glMatrixMode (GL_PROJECTION); // set the view volume shape
glLoadIdentity();
glOrtho (-2.0*64/48.0, 2.0*64/48.0, -2.0, 2.0, 0.1, 100);
glMatrixMode (GL_MODELVIEW); // position and aim the camera
glLoadIdentity();
gluLookAt (2.0, 2.0, 2.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glClear (GL_COLOR_BUFFER_BIT); // clear the screen
glColor3d (0,0,0); // draw black lines
axis (0.5); // z-axis
glPushMatrix ();
glRotated (90, 0,1.0, 0);
axis (0.5); // y-axis
glRotated (-90.0, 1, 0, 0);
axis (0.5); // z-axis
glPopMatrix ();
glPushMatrix ();
glTranslated (0.5, 0.5, 0.5); // big cube at (0.5, 0.5, 0.5)
glutWireCube (1.0);
glPopMatrix ();
glPushMatrix ();
glPushMatrix ();
glTranslated (0, 1.0 ,0); // torus at (0,1,0)
glRotated (90.0, 1,0,0);
glutWireTorus (0.1, 0.3, 10,10);
glPopMatrix ();
glPushMatrix ();
glTranslated (1.0, 0 ,0); // dodecahedron at (1,0,0)
glScaled (0.15, 0.15, 0.15);
glutWireDodecahedron ();
glPopMatrix ();
glPushMatrix ();
glTranslated (0, 1.0 ,1.0); // small cube at (0,1,1)
glutWireCube (0.25);
glPopMatrix ();
glPushMatrix ();
glTranslated (0, 0 ,1.0); // cylinder at (0,0,1)
GLUquadricObj * qobj;
qobj = gluNewQuadric ();
gluQuadricDrawStyle (qobj,GLU_LINE);
gluCylinder (qobj, 0.2, 0.2, 0.4, 8, 8);
glPopMatrix ();
glFlush ();
}
The main () routine initializes a 640-by-480 pixel screen window, sets the viewport and
background color, and specifies displayWire ().
In displayWire (), the shape and position of the camera are established first. Then each object is
drawn in turn.
Also shown in the figure are the x-, y-, and z-axes, drawn with conical arrow-heads. Displaying
the underlying coordinate system can help to orient the viewer. To draw the x-axis, the z-axis is
the underlying coordinate system can help to orient the viewer. To draw the x-axis, the z-axis is
o
rotated 90 about the y-axis to form a rotated system, and the x-axis is redrawn in its new
orientation. Note that this axis is drawn without immersing it in a glPushMaLrix (), glPopMatrix
() pair, so the next rotation to produce the y-axis takes place in the already rotated coordinate
system.
Fig 5.61 A simple 3D scene a) using a large view volume, b) using a small view volume
Two views of a scene are shown in Figure 5.61. Both views use a camera set by
Part (a) uses a large view volume that encompasses the whole scene;
Part (b) uses a small view volume that encompasses only a small portion of the scene, thereby
providing a close-up view.
The scene contains three objects resting on a table in the corner of a "room." Each of the three
walls is made by flattening a cube into a thin sheet.
The jack is composed of three stretched spheres oriented at right angles to each other, plus six
small spheres at their ends.
The table consists of a tabletop and four legs. Each of the table's five pieces is a cube that has
been scaled to the desired size and shape. The layout for the table is shown in Figure 5.62 and is
based on Four parameters that characterize the size of its parts: topWidth, topThick, 1egLen, and
legThick. A routine tableLeg () draws each leg and is called four times within the routine table ().
Always, a glPushMatrix (), glPopMatrix () pair surrounds the modeling functions to isolate their
effect.
.Fig 5.62 Designing the table
The complete code for this program is shown in Fig 5.63. The code shows the various things that
must be done to create shaded images. The position and properties of a light source must be
specified, along with certain properties of the objects' surfaces, in order to describe how they
reflect light.
<include <windows.h#
#include <gl/Gl.h>
#include <gl/Glu.h>
#include <gl/glut.h>
// <<<<<<<<<< wall >>>>>>>>>>>
void wall (double thickness ) {
// draw thin wall with top = xz-plane, corner at origin
glPushMatrix () ;
glTranslated (0.5, 0.5 * thickness, 0.5);
glScaled (1.0, thickness, 1.0);
glutSolidCube (1.0);
glPopMatrix ();
}
// <<<<<<<<<< tablfeLeg >>>>>>>>>>
void tableLeg (double thick, double len) {
glPushMatrix () ;
glTranslated (0, len/2, 0);
glScaled (thick, len, thick);
glutSolidCube (1.0) ;
glPopMatrix ();
}
//<<<<<<<<<< jack part >>>>>>>>>>>>
void jackPart () {
// draw one axis of the unit jack - a stretched sphere
glPushMatrix ();
glScaled (0.2,0.2, 1.0);
glutSolidSphere (1, 15, 15);
glPopMatrix () ;
glPushMatrix () ;
glTranslated (0, 0.1, 2) ; // ball on one end
glutSolidSphere (0.2, 15, 15) ;
glTranslated (0, 0, -2.4);
glutSolidSphere (0.2, 15, 15); // ball on the other end
glPopMatrix ();
}
//<<<<<<<<<<<<< jack >>>>>>>>>>>
void jack() {
// draw a unit jack out of spheroids
glPushMatrix () ;
jackPart ();
glRotated (90.0, 0, 1, 0);
jackPart ();
glRotated (90.0, 1, 0, 0);
jackPart () ;
glPopMatrix () ;
}
What changes should be made in Figure 5.63 to place the jack on the floor and the sphere
perched on top of the teapot?
Menus
The windowing systems support a set of widgets, which are special types of windows with which
the user can interact. Widgets sets include menus, buttons, slides bars, and dialog boxes. GLUT
provides limited capabilities, such as menu.
Suppose that we want to use the right mouse button to pop up a menu that will have two entries:
• Clear the screen.
• End the program.
glutCreateMenu (mymenu);
glutAddMenuEntry (“Clear Screen”, 1);
glutAddMenuEntry (“Exit”, 2);
glutAttachMenuEntry (GLUT_RIGHT_BUTTON);
When a window is created, it becomes the current window, the primitive are rendered to the
current window. We can change this window by:
We can also create sub-windows of any window. Each sub-window is defined to be a sub-
rectangle of its parent using:
int glutCreateSubWindow (int parant, int x, int y, int width, int height ) ;
Creates a sub-window of parent and returns its ID. The sub-window has its origin at (x, y) and
has size width by height in pixels. The sub-window becomes the current window.
Some Functions:
void glutIdleFunc (void (*f) (void)) ;
The function f() is executed whenever no other events are to be handled. When we want to
eliminate a callback, we call glutIdelFunction ().
// Menu Program
#include <GL/glut.h>
#include <stdlib.h>
GLsizei ww = 500, wh = 500;
int fill, r=1.0, g=1.0, b=1.0;
void fill_menu (int );
void color_menu (int );
void right_menu (int );
void display (void) {
glClearColor (0.0, 0.0, 0.0, 0.0);
glClear (GL_COLOR_BUFFER_BIT);
glColor3f(r, g, b);
if (fill == 1)
glBegin (GL_POLYGON);
else
glBegin (GL_LINE_LOOP);
glVertex3f (100.0, 200.0, 0.0);
glVertex3f (200.0, 200.0, 0.0);
glVertex3f (200.0, 300.0, 0.0);
glVertex3f (100.0, 300.0, 0.0);
glEnd();
glFlush ();
}
void init (void) {
glClearColor (0.3, 0.5, 0.3, 0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
}
void fill_menu (int id) {
if (id == 1)
fill = 1;
else
fill = 0;
glutPostRedisplay();
}
c_menu = glutCreateMenu(color_menu);
glutAddMenuEntry ("Red", 1);
glutAddMenuEntry ("Green", 2);
glutAddMenuEntry ("Blue", 3);
glutCreateMenu (right_menu);
glutAddSubMenu("Colors", c_menu);
glutAddSubMenu("Fill", f_menu);
glutAttachMenu (GLUT_RIGHT_BUTTON);
init ();
glutMainLoop();
return 0;
}
Dr
Taleb
Obaid
5 / 42