COMP 557 - Fall 2010 - Assignment 2
Perspective Projection Frustums, Depth of Field, and Anaglyphs
Due 12:00 Noon Wednesday 13 October
In this assignment you will use projection frustums to draw
a scene with blur due to depth of field, and to draw anaglyphs
that allow for 3D viewing with inexpensive colour filter glasses.
Download the sample code from WebCT. It is a working program that
will display a small test scene (you can change the scene if you
like). You will need to add the jogl, vecmath, and mintools jars to
your project. The sample code zip file contains only one class.
The sample code has several drawing modes which you change by entering
numbers 1 through 7. They are as follows:
- The world view (default) where you can use the trackball to see
the scene, the location of your frustums (as shown top right of this
- The view from the eye that lies on the z axis.
- The blurred depth of field view from the eye that lies on the z
- The view from the left eye.
- The view from the right eye.
- An anaglyph showing both left and right eyes in the same
- The combination of a depth of field blur for each eye show as
The first mode is the only mode that exists in the sample code. You
need to implement the others in the steps and objectives listed
below. To help with testing your assignment at the different steps,
you will be using Parameters
for various values, such as
the eye position, and the near and far planes (and many values).
You should notice that the provided code already uses the
class from the mintools jar. It creates a
window with controls for each of the parameters. When you call the
getValue method of a given parameter, you get the current value
which is set in the interface. You will also find IntParameter
useful for setting the number of samples in your rendering of blur,
BooleanParameter will be useful for enabling or disabling drawing of
viewing frustums. See the comments in the provided code.
Note that the current version of the mintools jar has a bug in
that the interface window initially shows all the sliders in the
middle position (i.e., a position that does not reflect their
current value). You will receive an updated jar to fix this problem.
You will want to use the following OpenGL calls to
complete the assignment:
You will need to set up several projection frustums by specifying
the left right top and bottom positions of the near plane, and the
position of near and far planes.
For depth of field, you will render the scene multiple times with
slightly different viewing frustums, and blend the results. The
accumulation buffer is a convenient mechanism for donig this. If
you're blending N images together, use glAccum(
GL.GL_LOAD, 1f/N ) to load the first image into the
accumulation buffer, and then gl.glAccum( GL.GL_ACCUM, 1f/N
) to add the contribution of the other renders. Remember to
use glClear before drawing each image, and use gl.glAccum(
GL.GL_RETURN, 1 ) to copy the result back into the frame buffer
once you're finished all rendering passes.
When drawing an anaglyph, you will want to draw one image for the
left eye, and a different image for the right eye. With
glColorMask you can enable or disable writing to different
components of the frame buffer. There are four components: red,
green, blue, and alpha. The alpha channel is used for transparency
and should always be enabled to allow for colour blending. Thus, to
draw only the red channel, call gl.glColorMask( true, false,
false, true ) before rendering the scene. To draw an image
into the green and blue chanells (cyan), then call
gl.glColorMask( false, true, true, true ), clear the buffer
with glClear, and draw the scene again with the projection
matrix for the other eye. Different glasses will have different
filters so you'll have to choose your colour masks according to
those that you're using (e.g., red/blue, red/cyan, or green/magenta,
where magenta is blue and red combined, and cyan is blue and green
You need to draw frustums in this assignment, and since you will
likely find it easier to use glFrustum to set up the
projection matrix, you will also want to use glGetFloatv
(with either GL_MODELVIEW_MATRIX or
GL_PROJECTION_MATRIX) to get a copy of this matrix in a
Java array. You can use the provided copyMatrixToFlat and
copyFlatToMatrix to convert between this row column OpenGL
format and a vecmath Matrix4f. You'll use the inverse of
your projection matrix, combined with glutWireCube(2) to
draw the frustum.
Steps and Objectives
In each step, you should be able to visually verify that your
implementation is working correctly.
Draw Screen Rectangle and Eye Point
Draw a white rectangle in the xy plane centered at the origin using
GL_LINE_LOOP. The x and y dimension should be equal to the width and
height of the display window in meters. Getting the screen dimensions
approximately correct is important for correct 3D viewing, so you'll
want to measure the width of your screen with a ruler and set the
variable metersPerPixel appropriately (see the commented
Draw a white sphere at the position of the eye using
glutSolidSphere. Note that with lighting disabled, it should just
look like a white circle, i.e., no shading. The radius should be
0.0125 meters to approximate the size of the human eye. Call
getValue on the eyeZPosition member variable to find
out where to draw the eye on the z axis.
Draw Frustum (2 marks)
In this step, you will want to create a projection matrix using
glFrustum that will be needed to project points on the screen. The
near and far parameters should be used to compute
the near and far plane positions. Notice that these near and far
plane positions are specified with respect to the origin, so you'll
need to add the eye position to compute the value to pass to
glFrustum. The motivation for defining these parameters in world
space is that they don't depend on anything. That is, when in mode 1,
world viewing mode, you can easily change the eye distance while
leaving the near and far planes fixed with respect to the screen
Note that since you must provide left, right, top and bottom of the
near plane, you will need to compute appropriate values to take into
account the position of the near plane with respect to the screen
rectangle (i.e., the screen rectangle should exactly fit inside your
Use the technique described in the assignment introduction to draw
a white wire frustum when drawCenterEyeFrustum is true. For
instance, you might first do a glPushMatrix, load the identity, set up
your frustum, then extract it with getDoublev, and then pop your
changes off the stack; then invert your matrix and put the inverse on
the stack along with any necessary translation to accommodate the eye
position, and draw a wire cube size 2 to show the region that will be
projected to normalized device coordinates.
You should also now implement viewing mode 2 which shows the result
of using this frustum. The easiest thing to do is overwrite the
opengl projection and modelview matrices to be your projection and
viewing transformation (i.e., the translation to the eye position).
Focal Plane Rectangle (2 marks)
Draw a grey rectangle to represent the focal plane. The focal
plane is in the xy plane, and at a displacement in z from the origin
specified by the focalPlaneZPosition parameter. You need to
compute the left, right, top, and bottom coordinates of the focal
plane so that it exactly fits inside your frustum. Try moving your
focal plane to different distances. Note that you should be able to
place it beyond your far plane, or in front of your near plane.
Eye Position Offset (2 marks)
In this step, you will use the x and y offset parameters
eyeXOffset and eyeYOffset to create a frustum at an
eye position that is displaced from its position on the z axis. The
idea is to explore the frustums which keep the focal plane rectangle
fixed while using different eye positions. In the next step, you'll
average together images created from many nearby eye positions while
keeping the focal plane fixed in order to create an image with a depth
of field effect. The purpose of this step is to make sure that you're
frustum is correct before proceeding.
Adjust your eye and frustum drawing code from previous steps to
account for the displaced eye position. Compute left, right, top, and
bottom values to pass to glFrustum to create the correct frustum which
always contains the focal plane. Test your code by moving the focal
plane and the eye offsets, and convincing yourself that it is doing
the right thing.
Depth of Field Blur
Implement viewing mode 3 by averaging multiple renders of the scene
with the accumulation buffer. Use the samples parameter to
get an integer number of samples to use in each axis direction, and
use the apertureSize parameter as the width and height of
the region in which you move the eye position. So with samples set to
3, you will render and average 9 images. Note that while using a
square aperture is easiest, you could also sample in a region of a
Draw Left and Right Eyes
This step can be done independently of steps 3, 4, and 5. For this
objective you must create frustums for left and right eyes. You
should display both eye positions and their frustums in the same way
as in step 2, but only if drawEyeFrustums is true. The
frustums should be colour coded according to the glasses that you are
using, so if the filter for your left eye is red, then you should draw
the left eye frustum and left eye position in red.
The frustums should both contain the screen rectangle, thus you'll
need to compute correct left, right, bottom, and top values for each.
The eyeDisparity parameter should be used to set the distance
between the eyes (default of 63 mm), so the left eye should be half
this distance in the negative x direction, while the right eye should
be half this distance in the positive x direction (i.e., the center
point between the eyes lies on the z axis).
Note that if we were able to track the eyes, then we might want to
use the known position of each eye in setting up the frustum.
However, we will just assume that the viewer is sitting exactly in
front of the screen at a distance from the screen specified by
Test that your frustums are correct by adjusting the near plane, and by
viewing the resulting images with viewing mode 4 and 5.
Combine the images you render for mode 4 and 5 by using the
appropriate glColorMask calls. Test your image using colour glasses.
You should be able to make objects appear both behind and in front of
the screen. Be sure you do not have your left and right eyes
reversed! The eyeDisparity parameter value should always be
a positive number.
Anaglyphs with Defocus (optional, 5% bonus)
Combine your efforts in the previous step to create anaglyphs
where the left and right images have blur due to depth of field. The
trick is to define your frustums correctly. The offsets you use to
create the blurred image need to keep the focal plane rectangle fixed,
but this focal plane rectangle is different for each eye as it is
defined by the eye position and the screen rectangle position.
Readme File (0 marks, yet not optional)
Create a readme.txt or readme.pdf file to
submit with your assignment. The readme should include any
comments you have with respect to the assignment, and describes
anything you deem to be noteworthy. Try to be brief!
Great! Be sure your name and student number is in the window
title, in your readme, and in the top comments section of each of
your source files.
Submit your source code as a zip file via webCT. Include a
readme.txt or readme.pdf file with your
comments. Be sure to check that your submission is correct
by downloading your submission from WebCT. You cannot
receive any marks for assignments with missing or corrupt
Note that you are encouraged to discuss assignments with your
classmates, but not to the point of sharing code and answers.
All code and written answers must be your own.