Home | | Syllabus | |
Assignments | | Lecture Notes | |
Documentation
Assignment 4
Due: Thursday, October 19, in class
Problem 1:
In this problem, you will use WebGL to create a 3-Dimensional object
that rotates about different axes depending on a key-press. You will first create
a simple 3D box, open at the top and bottom, then you will add the code that allows it to rotate.
Finally, you will write a program that recursively divides each of the quadrilateral faces
into two new quads, generating the approximation of a cylinder (that is open at the top
and bottom).
Part a. A spinning box.
Write a program similar to the example program for a spinning 3D color cube
from chapter 4 of the text (cube.html and cube.js).
This program should create a box, with 4 quadrilateral faces that is open at the
top and bottom (so you need to remove the top and bottom faces from the cube).
Make your box centered
on the origin. Make sure the faces of the box are created so that the "outward" face is
toward the outside of the object. (Use the right-hand rule to make sure you list the vertices
in the correct order to accomplish this). Alternate the colors of the sides between red
and blue so that you can see the
three-dimensionality of the box. You will need to change the VertexColors array
to accomplish this. You should be able to use the buttons (that were already there
from cube.html) to see the rotation
of the box around different axes. Save this file as box.js and box.html.
The following image shows the box viewed at an angle from the top:
Part b. Add a keypress option to the user interface
Save the program you wrote in part a into new files called, spin.js and spin.html. Modify this
program to include a user-interface that detects a keypress. A press of the 'f' key should
cause the box to spin about the x axis. The 'j' key should cause spin about the y
axis and the 'k' key should cause spin about the z axis. To respond to a keypress, use
the function: window.onkeydown = keyResponse, where keyResponse() is the event listener for a
keypress. An example of responding to a keypress is given in the textbook, page 120 and
provided in the rotatingSquare2.js program from Chapter 3.
You can get the key value by using the following command:
var key = String.fromCharCode(event.keyCode);
Be aware that the string that is returned is a capitalized letter even if the user does not hold
down the shift key.
To make it so that the box only spins when a key is being held down, you should remove the
angle increment (theta[axis] += 2.0;) from the render( ) function, and place it in each
case of the switch( ) statement in the keyResponse( ) function. That is, for each key, you
should change the axis of rotation and increment theta for that axis. If the user holds the
key down, the keyResponse( ) function will be called repeatedly to show the spinning box.
Save the code for this part in files called spin.html and spin.js
Part c. Approximating a cylinder
One way to generate a sphere in openGL, is by successively dividing triangular faces
of a polyhedron into more triangles, and normalizing all the vertices so that they lie
on the surface of a sphere. An example of this approach is described in the textbook
in section 6.6 and the program is given in
the shadedSphere1.js file in the chapter 6 examples from the textbook.
In this part of the problem, you will use a recursive strategy similar to that
in the Sphere program to approximate a cylinder. Instead
of using the divide_triangle function to recursively divide the object into triangular
faces, you will write a recursive divide_quad() function that will recursively divide
the quadrilateral faces of your box into 2 new quadrilateral faces.
Save the code from part b into two new files, called
cylinder.js and cylinder.html. First, you will need to normalize the vertices of your
box so that they all lie an equal distance from the y axis. If a vertex is at
position (x, y, z), and you want it to be a distance, d, from the y axis, you can normalize
by multiplying the x and z components by d/(sqrt(x*x + z*z)). Make sure none of your vertices
is at the point (0, 0, 0) before doing this! Second, create a recursive
function, divide_quad(), that takes four vertices and an integer counter as parameters.
divide_quad() should calculate two new vertices from the four given as parameters, one at
the center of the top edge and one at the center of the bottom edge. These new vertices
should then be normalized
to be at the same distance from the y axis as the others. The new vertices, along with pairs
of the other four vertices, define 2 new quadrilaterals as shown below.
If the recursive counting variable is greater than zero, these two new quads should
be divided (by calling divide_quad with the new sets of vertices). This is then repeated
for as many levels as defined by the counter. (I recommend trying small numbers, like 0, 1 and 2
levels, to test it out). When the counter reaches zero, render the current quadrilateral
from the four vertex parameters (by calling the quad( ) function). Below is the resulting object
for m=1, viewed at an angle
from the top.
You will need to specify a unique color for each face of your cylinder. I recommend
alternating the color between two primary colors such as red and blue. You can do this
by passing the color as a parameter to the divide_quad( ) function. Pass red to
the first divide_quad() call and blue to the
second call to divide_quad(), and so on. When the number of levels reaches zero, divide_quad( )
should pass the current color on to the quad( ) function.
Problem 2: Gimbal Lock
If you examine the html file for the color cube, you will see that the way the
cube is made to spin about the three
different coordinate axes, is by multiplying each vertex by the three rotation matrices in order:
gl_Position = rz * ry * rx * vPosition;
This implementation leads to an interesting phenomenon, known as gimbal lock, which
occurs in the following situation. If the user presses a key (the 'j' key) to rotate
the object by -90 deg (In this implementation, the ry rotation actually rotates in the clockwise direction, so it is a rotation
by a negative angle)
about the Y axis, then subsequent rotations about the X or Z axis will appear to have the
same effect--i.e. the object will appear to rotate about the same axis for either key press.
What is going on here?
Your task is to show that gimbal lock is a direct consequence of multiplying the three rotation
matrices together in the vertex shader.
Note that the program will perform the rotations in the same order
(First about X, then about Y and finally about Z) when drawing the object, independent of
the order in which the user pressed the keys. Use the matrix equations for the transformations
in the three rotations to show that the sequence Rz(theta)Ry(-90)Rx(0) is equivalent
to the sequence Rz(0)Ry(-90)Rx(theta). (You need to do the matrix multiplication on this one to
show that the results are the same). Write out the matrix equations and their solutions.
Problem 3: Camera Position based on Yaw, Pitch and Roll.
In section 5.3.4 of the textbook, the concept of Yaw, Pitch and Roll are defined in terms
of an aircraft. If the airplane is pointing along the positive Z axis, then yaw is a rotation
about the y axis, pitch is rotation about the x axis and roll is rotation about the z axis. Note that
the "camera" in this case is in the nose of the plane, which is not centered at the origin.
Given three angles, theta1, theta2, and theta3 that define the amount of yaw, pitch and roll,
respectively, and a distance d of the nose of the airplane from its center of mass (located
at the origin), write the matrix multiplication equation that sets up the camera in the viewing
position that corresponds to the yaw, pitch and roll (in that order). Hand in the equation,
showing the complete matrices that are multiplied together. Assume that the initial position
of the camera is located at the origin and that it is pointing toward the positive Z axis (Note
that this is the opposite to the default openGL camera direction, which points toward the negative
Z axis). You do not need to multiply out
the matrices.
Turning in this assignment
- Turn in a hardcopy of the html and javascript code for problem 1, for the cylinder program only.
- Turn in the written answer and your derivation for problem 2.
- Turn in your written answer and derivation for problem 3.
- Turn in a discussion log.
- Bring these to class on the due date.
- Upload soft copies of box.js, box.html, spin.js, spin.html,
cylinder.js and cylinder.html to Canvas.
Home | | Syllabus | |
Assignments | | Lecture Notes | |
Documentation
Constance Royden--croyden@holycross.edu.edu
Computer Science 343
Last Modified: October 4, 2023
Page Expires: August 17, 2024
|