[Previous Section] [Next Section]
We consider the OpenGL model of Transformations, and how it is used. We will also consider its pixel map functionalities.
[Previous Section] [Next Section]
There are several coordinate systems in OpenGL and it is important to keep them straight. We have:
1.1 World Coordinates and Local Coordinates.
When you construct a geometric object, it is placed in this coordinate system. To illustrate this idea, it is enough to consider 2D. Suppose you want to model a house, whose outline is just given by a hexagon:
Here w, h represents the width and height of the house,
and rw, rh are parameters related specifying the roof of the house.
But what if you want to have several copies of this house
in our scene? We may want to scale and
rotated the house to rest on a hill slope, etc.
We will see how to do this. This means we want to think
of the overall model (``the world'' or ``the scene'')
as comprising one or more local objects (like the house above).
For this reason, we sometimes call the coordinate system of
the house the local coordinates. A local coordinate
can be instanced in the world coordinate system any number
of times.
OpenGL gives us two sets of tools to achieve this.
(1) Display Lists and (2) Matrix Transformations.
Here is a simple example:
instancing houses
from the previous lecture. In particular, notice how we wrap
the object within a display list.
In the program, it was a cube, but it could be our house,
with some unique identifier MY_HOUSE.
Then we call to display it this:
What is the matrix being manipulated? This
is the MODELVIEW matrix, described below.
There is also a PROJECTION matrix.
More about
Display Lists.
This is perhaps the easiest to understand among
the coordinate systems. For one thing, it is 2D.
It corresponds to the physical display in a one-to-one manner.
This is a integer-based coordinate system, with each
integer point (x,y) corresponding to a pixel on the screen.
In OpenGL we have two slight complications:
first, modern displays do not just take over the entire screen.
So each application is given control of
a portion of the screen, which we call a window.
But since the word ``window'' is over-used, we may say
screen window to be specific.
The coordinate system within each window is
called its window coordinates.
Following graphics convention, window coordinates for
increasing x-coordinates goes from left to right,
and increasing y-coordinates goes from top to bottom.
Thus, the top-left corner of a screen window is denoted
(0,0) in the window-coordinates.
Note that in mathematical conventions, y-coordinates
goes from bottom to top. OpenGL will use both conventions,
depending on whether we are in screen coordinates or not.
The second complication is this: in OpenGL, each window itself can
be used for several subwindows called viewports. So,
what OpenGL displays is really in a specific viewport in
a specific screen window! There is no need for a viewport
to even fit in a window, but then you will not see those
parts that do not fit.
We remark that the screen windows need not be disjoint
among themselves. The way to display any screen window
is therefore through some priority mechanism
based on ``depth'' (above/below relation).
It is tempting to thinkg of viewports as subwindows within
a screen window. But it is simpler than this, and amounts
to a ``current transformation'' which we will explain.
Here is how you set up a screen window in OpenGL/GLUT:
The first two steps are mandatory, but the next three steps have
default values that are assigned if you do not specify them.
Question: where is the viewport in the above in the above
setup? If we do not specify it, it defaults to the entire window!
Here is a typical use of viewport: suppose you have an image
to display and it has a particular aspect ratio R = Width/Height.
If the user resize the window to a different aspect ratio, the
image will be distorted. To avoid this, you set up the
display callback function to use a viewport with the correct
ratio R, and that is maximized to fit the current window.
See [Hill, Chap.3.2.2, p.92].
REFERENCE: [Hill] (Parallel projection in Sect 5.6.2, p.263,
Perspective projection in Section 7.2).
After subjecting our models to a series of tranformations,
we have a model transformation matrix M.
Each point p is transformed to Mp in world corrdinates.
So far, this modeling is independent of the eye
position. For instance, if the
eye were to look in the −z direction,
and is placed at (1,0,0), then relative to the
viewpoint of the eye, each Vertex (x,y,z)
appears as (x−1, y, z). Thus the position of the eye,
in eye coordinates is at (0,0,0).
In the simplest case, this amounts to a
translation. But in general, this is specified by
a view tranformation matrix V.
Then a point p is now transformed
to VMp. In OpenGL, the combination of V and M
is called the modelview matrix.
Now the name ``Model + View'' is clear.
There are several convenient API's for setting up V.
In general, the eye parameters can be specified by three
vectors:
glBegin(GL_POLYGON);
glVertex2d (0, 0);
glVertex2d (w, 0);
glVertex2d (w, h);
glVertex2d (w-rw, h+rh);
glVertex2d (rw, h+rh);
glVertex2d (0, h);
glEnd();
glPushMatrix();
glLoadIdentity();
glRotatef(theta, 0.0, 0.0, 1.0); // angle theta
glScalef(2.0, 2.0, 2.0); // double its size
glCallList(MY_HOUSE);
glPopMatrix();
1.2 Window Coordinates.
// SETTING UP A SCREEN WINDOW
glutInit(argc, argv); // C/C++ command line arguments
glutCreateWindow("My Screen Window"); // window with title
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(640, 480); // screen width and height in pixels
glutInitWindowPosition(0,0); // position of top-left window corner
// SETTING UP VIEW PORT
glViewport(GLint x, GLint y, GLsizei w, GLsizei h);
// (x,y) is the top-left corner of viewport
// in screen window coordinates
1.3 Eye Coordinates
The world coordinate system is potentially infinite and 3D.
We have now to worry about projecting it to a finite 2D viewport.
The first step is to make the world finite. This depends
on the viewing parameters, of which the
previous eye parameters is only one part.
What is missing is the
choice of projection, view angle, and visual limits (how far or
how near we can see).
These parameters are needed to create an image.
Here, we need to distinguish two basic projections:
parallel projection and
perspective projection. Mathematically, they
can be unified, but in practice, we keep them apart.
The desired portion is called the
view volume which is geometrically a frustum.
Once we specify this volume, we can map this volume into our viewport.
This is the projection operator, again specified by
a matrix P. A point p is then transformed as
Again, we have API to help us define the view frustum.
The simpliest is a rectangular parallelepiped
(with a left-side, right-side, top-side and bottom-side),
cut off by a near plane and a far plane.
Note that these coordinates are relative to the eye (the origin).
This is not a completely general frustum, clearly.
But there is no assumed symmetry about the origin.
The near plane is z=−zmin, and the far plane is z=−zmax,
so they are assumed parallel to the z=0 plane.
Alternatively, if we need a perspective view, we need a
frustum with non-parallel faces. The corresponding API is
Now, this volume can be transformed so that it
has a particular location in world coordinates.
This transformation
is called the eye-coordinates.
If we are only interested in 2D images, we
can simplify this using an API in the GLU library.
We have already seen examples of this usage:
WHAT ABOUT THE VIEW PLANE?
To some extent, it does not matter what this is.
The main reason is that
we ALWAYS ASSUME IN OPENGL that this plane is normal to
the z-axis of the eye coordinates. Thus the choice of the choice
of the viewplane, intersected against the view frustum,
only determines the size of the image. But
this is already automatically controlled by our
viewport transformation. There is ONE subtlety:
under projective transformation, if this viewplane is
behind the eye position, then everything appears
inverted. But the default is to choose some plane in front
of the eye.
The objects we construct (which ultimately
reduces to Vertices) are subject to a sequence of transformations,
as illustrated in the
OpenGL specs.
EXERCISES
Q1. Determine all the default screen window parameters in GLUT.
Q2. How do you use several windows in GLUT?
See below.
Q3. Study the Camera class introduced by Hill (section 7.3, p.366).
[Previous Section]
[Next Section]
We can use Transformations to achieve the following effects:
[Previous Section]
[Next Section]
[Previous Section]
[Next Section]
[Previous Section]
[Next Section]
Suppose you have created a window called
mainWin:
Note that when we have only one window,
we ignore the unique integer identifier
that is returned by glutCreateWindow(); but
you now need to refer to this identifier.
Here is how you can create a
subwindow called button which
is supposed to be a little square which turns
on or off in response to mouse clicks.
In the presence of several windows, GLUT needs to know
which subwindow is the ``focus'' of attention at any moment;
The last function glutSetWindow() above
is used to set the focus.
[Previous Section]
[Next Section]
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(eye_x, eye_y, eye_z,
at_x, at_y, at_z,
up_x, up_y, up_z);
NOTE that this transformation (i.e., V) is applied
after all the model transformations (i.e., M) is applied.
1.4 View Volume
PVMp = P(VM)p
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(xmin, xmax, ymin, ymax, zmin, zmax);
glMatrixMode(GL_MODELVIEW); // restore default matrix
gluPerspective(fov, aspect, near, far);
The parameters near, far are similar to zmin, zmax before.
The fov parameter (field-of-view) here specifies the
vertical angle spanned by the eye, symmetric in the horizontal
direction.
The value of aspect gives
us the aspect ratio (which combined with fov) gives
us the horizontal angle spanned at the eye.
``Vertical'' and ``horizontal'' makes sense relative to the
up direction, which recall,
is part of the eye parameters.
glOrtho(left, right, bott, top, near, far);
gluOrtho2D(left, right, bott, top);
1.5 The OpenGL Pipeline
2 Applications of Transformations
3 Lighting
4 ADDITIONAL NOTES
5 Working with Subwindows
int mainWin;
mainWin = glutCreateWindow(argv[0]);
// ON/OFF button
button = glutCreateSubWindow(mainWin, 300, 0, 20, 20); // size = 20x20
glClearColor(0.0, 0.0, 0.5, 0.0); // background color
glutDisplayFunc(displayButton); // callback for displaying subwindow
glutReshapeFunc( buttonReshape ); // callback for reshaping subwindow
glutSetWindow(mainWin); // reset the focus to main window
6 Getting Started