Recap of Camera API

Relativity

Are you moving the camera or the scene? In some sense it doesn't matter, but sometimes it can be very confusing. If the scene is a globe and I'm looking at North America from space, and I do

glRotatef(45,0,1,0);
am I now looking at Europe or the north Pacific? Think about this, and we'll discuss it in class.

That's why it's called the GL_MODELVIEW matrix: it combines both modeling and viewing.

The Viewport

Last time we discussed both perspective and orthographic projections. Having mapped the scene to the image plane using either of these projections is not the end of the story. The 2D image is then mapped onto the window that we opened at the beginning of our program. More precisely, it is mapped onto a viewport. That is, you don't have to draw on the entire window. You can draw instead on a "viewport," which is a rectangular region of the window. You specify this with the following call:

glViewport(left,bottom,width,height);

The arguments are in pixels! This is the first time we've used pixels in this course! Consult the man page for more information. If you want to use the whole window, you certainly may. That's the default, so specifying a viewport is optional.

Note that, most of the time, the viewport is your whole window, so left and bottom are both zero, and width and height are the width and height of the window.

Aspect Ratio

There's a very key idea contained in this mapping from the top of the frustum and the viewport. Consider a frustum that is square and a viewport or window that is decidedly not square: suppose that it is twice as wide as it is high.

The aspect ratio of a rectangular region is the ratio of the width to the height.

How are movies different from TVs? Why does a movie have to be "formatted to fit your TV?" How is it reformatted?

The top of the frustum is always plus/minus 1 to plus/minus 1 on the X and Y dimension (Z having been eliminated). These are called normalized device coordinates

Assume that the viewport is defined as (1,2,20,10). To what pixel coordinates does (0.25,0.75) map to? Sketch a picture of this.

Demo

pytw/demos/camera/FrustumModes.py shows the effects of different ways to handle the aspect ratio of the window. Again, use the "?" key to find out the callbacks. In this case, there are keys that change whether you are letterboxing, clipping, or distorting. You can also change the figure being displayed.

The Reshape Callback

Okay, you've got the top of your frustum in the same shape as your viewport, to avoid distortion, but what if the user reshapes the window?

You can handle that with a reshape callback, another of the X events to which your program can respond, like the display and keyboard callbacks. The function gets the new width and height of the window.

Look at the way TW handles it in pytw/TW.py (search for twReshapeFunction): Essentially, all it does on the reshape is to set the values of some global variables. One of those variables, aspectRatio is used in the twCamera() function. That function also allows three modes of viewing: letterbox, distort and clip (truncate).

Multiple Viewports

By using the viewport more than once, you can draw the same scene multiple times or different scenes. An example is pytw/demos/camera/Viewports.py. However:

In short, subwindows are easier.

Sub-windows

We saw this earlier in pytw/demos/camera/Perspective.py. You use subwindows as follows:

Projection

You can ask OpenGL to project something for you, yielding window coordinates in pixels. You can also, believe it or not, unproject, but to do that you have to supply a "depth."

Projection involves:

In Normalized Device Coordinates, all coordinates are between -1 and +1. You can think of this as a reshaped frustum, allowing us to do a parallel projection of the reshaped frustum. So, in fact, we can retain depth information until the very end.

Look at the twProject function: tw/src/tw-camera.cc

UnProjection

You can also go in reverse, mapping a 2D point on the screen to a 3D point in space. Obviously, that's impossible, because there are an infinite number of points that project to a point on the screen. More precisely, there is a line segment (from the near face of the frustum to the far face) that projects to a point. To resolve the ambiguity, requires starting with a "depth," which you may not have.

Why would you do this?

In interacting with the mouse (we'll get to that soon), we often want to know the relationship between where the mouse clicked (mouse coordinates in pixels) and the objects in the scene. That relationship is exactly the projection/unprojection relationship.

Next week, we'll look at how we use the mouse to rotate the scene.

Camera Setup

Let's open the covers of our black box and look at how the TW layer sets up the camera for us.

Depth

So, how does OpenGL handle depth?. That is, two figures (say teapots) project onto overlapping pixels. One teapot is red, the other is green. How do you determine the color of the pixels in the overlap?

  1. Draw the figures in back to front order. What's the problem with this?
  2. Keep track of the "depth" of each pixel and color the pixel with the color of the nearer surface.

The latter is called the "z" buffer algorithm, because in normalized device coordinates, z is depth. We keep a buffer of z values in 1-1 correspondence with the frame buffer.

To use this, we have to:

Let's look at the code in pytw/TW.py to see these last two features.

Written by Scott D. Anderson
scott.anderson@acm.org
Creative Commons License
This work is licensed under a Creative Commons License.

Valid HTML 4.01!