CSCI 343 Computer Graphics

    College of the Holy Cross, Fall 2023

    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:

    1. Rotate the box about the X, Y and Z axes by the amount given by theta (as in the original code).
    2. Translate the box upward by 100.0 units (in the positive Y direction).
    3. 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:
    1. 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).
    2. Translate the object so that the light source is at the origin: T(-xl, -yl, -zl).
    3. Multiply by the projection matrix, m.
    4. Translate back: T(xl, yl, zl).
    5. 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