Home | | Syllabus | |
Assignments | | Lecture Notes | |
Documentation
Assignment 5
Due: Thursday, October 26, in class
Problem 1: Perspective Projection.
In this problem, you will render a 3D Pyramid on the screen using perspective
projection.
Download the
simpleBox.zip file that contains both the html and javascript files
to render a simple box like the one you created in assignment 4. Note that the user interface
has the box rotate around different axes when you press a key valued between 1 and 6. E.g. pressing
the '1' key will rotate around the X axis in a positive direction and the '2' key will rotate the
box around the X axis in the negative direction. You will modify this program to draw a 3D pyramid
and use perspective projection to render it. You will also add to the user interface so that
you can move the pyramid forward, backward, up, down, left or right.
Do this in three steps: First, change the code to draw the 3D pyramid.
Second, convert the projection
to a perspective projection. Third,
add to the user interface to move in the different directions. Before you begin, change the name
of your files to pyramid.html and pyramid.js. Make the appropriate modification to pyramid.html
so that it references the pyramid.js file.
Step 1. Drawing a 3D pyramid.
Up until now we have always worked within the canonical clipping volume, which is a 2x2x2 cube
centered on the origin. With our projection matrices we will be freed of this constraint. Write
code to draw a four-sided pyramid with a square base. The tip of the pyramid should be located
at (0, 100, 0). The vertices for the base of the pyramid should be located at (0, 0, 100),
(-100, 0, 0), (0, 0, -100) and (100, 0, 0). You can use the quad( ) function to draw the base.
You might want to write a triangle( ) function to draw the four sides. Make each side a different
color, and the base a different color from all the sides.
Step 2. Add code for Perspective Projection.
First, in the pyramid.html file, add a uniform variable to the vertex shader that will get the projection matrix,
e.g.
uniform mat4 projection;
In the main( ) function of the vertex shader, multiply each vertex by the projection matrix and
the modelView matrix:
gl_Position = projection*modelView*vPosition;
Next, in the pyramid.js file, use the function, perspective(fovy, aspect, near, far) to set up the perspective
projection clipping volume, where fovy is the vertical field of view (in degrees)
of the clipping
volume, aspect is the aspect ratio for the width/height, and near and far
indicate the
near and far clipping planes. Keep in mind that near = -zmin and far = -zmax. Thus, for
a clipping volume that can be seen by the camera (along the negative z axis), zmin and zmax
will be negative numbers but near and far are given as positive numbers. Set up the
perspective viewing so that fovy = 45 degrees, aspect = 1.0, near = 1.0 and far = 500.0. You
can call perspective() in the render() function and assign the result to a variable (e.g. pMatrix).
In the init( ) function, access the projection matrix from the vertex shader with a call to:
projection = gl.getUniformLocation( program, "projection" );
(make sure you have declared a global variable named projection).
Next, in the render( ) function, assign your pMatrix to the vertex shader with the call:
gl.uniformMatrix4fv( projection, false, flatten(pMatrix) );
Finally, set the camera position by translating the entire scene by -300 units along the Z axis.
This will move the pyramid away from the origin so that the camera can see it. Make sure the
translation occurs last, after any rotations (so the matrix multiplication for this translation
will take place first).
Step 3. Add keyboard choices to translate the pyramid along different axes
Modify the keyboard function to change the pyramid's position along the x, y and z axes
when you press the appropriate keys, as follows.
- 'F': Move forward (increment Z)
- 'B': Move backward (decrement Z)
- 'U': Move up (increment Y)
- 'D': Move down (decrement Y)
- 'R': Move right (increment X)
- 'L': Move left (decrement X)
Part b. Questions about the perspective projection in the above problem.
1. The clipping volume created by perspective(fovy, aspect, near, far) is in the shape
of a frustum. What are the values of xmin, xmax, ymin and ymax for the near plane of the clipping
volume created by the call to perspective(45, 1, 1, 500)?
2. Why did you initially translate the pyramid by -300 along the Z axis?
What would happen if
you had not done this translation?
3. If you rotate the pyramid 45 deg about the Y axis, so that a single side is in view,
and then hold down the 'b' key for a long time, the pyramid appears to move away
from the camera, i.e. it gets smaller. After a while, the top of the pyramid gets flattened
As the pyramid moves further away, the top gets flatter. Why does this happen?
Write the answers to the above questions and turn them in with the hardcopy of your
program.
Problem 2: A simple shadow projection.
In this problem we will use the projection technique discussed in lecture and in
section 5.10 of the book to create a shadow of the box on the x-y plane.
We will start with the box, that you will be able to spin about the three major axes
with a keypress of the 1 - 6 keys as in the above problem.
Download the shadowBox.zip file. When expanded, this
contains the html and javaScript source code to
render a box that spins in response to a keypress.
Use the following steps to create a shadow on the x-z plane.
Step 1. Set the position of the light source
Create a global variable that indicates the x, y and z position of the light source
(e.g. use a 3-element array). Set the position of the light source to (0.0, 250.0, -50.0).
The second element of this array should be used in the computation of -1/yl in matrix m
for step 2.
Step 2. Create the projections matrix, m.
In your init( ) function, create a matrix, m, that sets up the 4 x 4 projection matrix that will
project the shadow along the y axis onto the x-z plane (as described in lecture
and in section 5.10 of the book). Make
sure m is a global variable. Use the global variable for the lightsource from part 1 to calculate
-1/yl.
Step 3. Position your box
The box should be rendered as in the original shadowBox.js file.
However, the following transformations should be applied:
- Rotate the box about the X, Y and Z axes by the amount given by theta (as in the original code).
- Translate the box upward by 100.0 units (in the positive Y direction).
- Rotate the box by 30.0 degrees about the X axis.
Remember to list the transformations in the reverse order in which they will be applied
to the box! The last transformation--the rotation about the x axis--is used so that
we will be able to see the x-z plane in the final rendering.
Step 4. Draw the shadow
Now you will redraw the box as a projected shadow. In the render function, after the call
to gl.drawArrays( ) that renders the 3D box, assign the identity matrix to the mvMatrix variable
using a call to mat4( ):
mvMatrix = mat4( );
You should apply the following transformations to
obtain the correct shadow of the box:
- Do the first 4 transformations that were done for the box object above. (I.e. the rotations
about the three axes and the translation upward by 100 units).
- Translate the object so that the light source is at the origin: T(-xl, -yl, -zl).
- Multiply by the projection matrix, m.
- Translate back: T(xl, yl, zl).
- Rotate by 30.0 degrees about the X axis.
Again, remember to reverse the order of transformations in your code. The last
rotation (about the X axis) is so that we can see the x-z plane. In orthographic projections,
a plane that is perpendicular to the projection plane is invisible. The final rotation rotates
the shadow and the box so that the plane of the shadow is no longer perpendicular to the
viewing plane.
After the transformations are specified, re-draw all the faces of the box. You must first call:
gl.uniformMatrix4fv( modelView, false, flatten(mvMatrix) );
to reset the transformation matrix. You should then redraw the box using a call to gl.drawArrays( ),
as before.
Step 5. Color the shadow gray
The projection from part 4 still has the colors of the original box. To make the shadow gray, we
will create a second color array that has gray as the color for each vertex, and we will switch back
and forth between the two color arrays in the render function. Do this with the following steps:
- Add a global variable named shadowColors that is an array.
- In the quad( ) function, each time you push a color onto the color array, add a line to
push gray (vec4(0.3, 0.3, 0.3, 1.0)) onto the shadowColors array.
- In the render function add two lines of code to bind the colors array to cBuffer before
drawing the 3D box with gl.drawArrays:
gl.bindBuffer( gl.ARRAY_BUFFER, cBuffer );
gl.bufferData( gl.ARRAY_BUFFER, flatten(colors), gl.STATIC_DRAW );
Note that cBuffer must be a global variable because the code that associates it with vColor in the
shader is part of the init( ) function.
- In the render function, add an additional two lines of code to bind the shadowColors array before drawing
the shadow. Use the two lines above, but with the shadowColors array instead of the colors array.
When you are finished, you should have a box with a gray shadow below it. The following image shows
what it looks like after rotating about the Y axis:
Save your code in the files, shadowBox.html and shadowBox.js.
Turning in this assignment
- Turn in a hardcopy of the html file and the javascript file problem 1 (pyramid.html and pyramid.js)
and the html and javascript files from problem 2 (shadowBox.html and shadowBox.js).
- Turn in the written answers to the questions in problem 1.
- Turn in a Discussion Log.
- Bring these to class on the due date.
- Upload a copy of the pyramid.html and pyramid.js, shadowBox.html and shadowBox.js
files to Canvas.
Home | | Syllabus | |
Assignments | | Lecture Notes | |
Documentation
Constance Royden--croyden@holycross.edu.edu
Computer Science 343
Last Modified: October 19, 2023
Page Expires: August 17, 2024
|