Program 2: on rasterization — due October 21 (updated)

(updated on Tuesday Oct 4 to include new programming shell)

Due: 11:59pm, Friday October 21

Goal: In this assignment you will practice basic modeling and implement transforms and lighting on 3D objects using the WebGL rasterization API.

Submission: Submit your assignment using Wolfware Classic. The submit locker is now available. Click on "Submit Assignments" next to "Grade Book".

The main components of this programming assignment are:
  • 10% Part 0: properly turned in assignment
  • 10% Part 1: render the input triangles, without lighting
  • 20% Part 2: model and render the input spheres, without lighting
  • 20% Part 3: light the spheres and triangles
  • 20% Part 4: interactively change the view of the spheres and triangles
  • 20% Part 5: interactively transform the spheres and triangles
  • Participation: Receive participation credit (outside of this assignment) for posting images of your progress, good or bad, on the class forum!

You will only render triangles and spheres in this assignment, described in the same sorts of JSON input files used in the first. We will test your program using several different input files, so it would be wise to test your program with several such files. The input files describe arrays of triangles and spheres using JSON. Example input files reside at and When you turn in your program, you should use these URLs in hardcode as the locations of the input triangles and spheres files — they will always be there. While testing, you should use a different URL referencing a file that you can manipulate, so that you can test multiple triangles and sphere files. Note that browser security makes loading local files difficult, so we encourage you to access any input files with HTTP GET requests.

We will shortly provide a small shell in which you can build your code. You can run the shell here, and see its code here. The shell will show shows how to draw a triangle using WebGL without any model or view transform, and how to parse the input triangles.json file.

The default view and light are as in the first assignment. The eye is at (0.5,0.5,-0.5), view up of [0 1 0], look at vector [0 0 1]. The window has XY view coordinates (0,1,0,1), and is located at view Z=0. Once more, with this default view everything in the world is in view if it is located in a 1x1x1 box with one corner at the origin, and another at (1,1,1). Put a white (1,1,1) (for ambient, diffuse and specular) light at location (2,4,-0.5).

You should code the core of this assignment yourself. You may not use others' code to transform or project models or perform Blinn-Phong lighting. You may use math, matrix and modeling libraries you find, but you must credit them in comments. You may recommend libraries to one another, speak freely with one another about your code or theirs, but you may never directly provide any code to another student. If you are ever uncertain if what you are contemplating is permissible, simply ask me or the TA.

Part 0: Properly turned in assignment
Remember that 10% of your assignment grade is for correctly submitting your work! For more information about how to correctly submit, see this page on the class website.

Part 1: Render the input triangles, without lighting
Use rasterization to render unlit triangles, giving each triangle its unmodified diffuse color (e.g, if the diffuse color of the triangle is (1,0,0), every pixel in it should be red). You will have to use vertex shaders to perform viewing and perspective transforms, and fragment shaders to select the diffuse color. We recommend the use of the glMatrix library for creating these transforms.

Part 2: Render the input spheres, without lighting
Use rasterization to render unlit spheres, giving each sphere its unmodified diffuse color. There are no sphere primitives available in WebGL, so you will have to build a sphere out of triangles, then transform it to the right location and size. You can do this statically with a hardcoded sphere model, or procedurally with a latitude/longitude parameterization. Again you will have to use vertex shaders to perform viewing and perspective transforms, fragment shaders to select color.

Part 3: Light the spheres and triangles
Shade the spheres and triangles using per-fragment shading and the Blinn-Phong illumination model, using the reflectivity coefficients you find in the input files. Use triangle normals during lighting (which will reveal faceting on your spheres). Your fragment shaders will perform the lighting calculation.

Part 4: interactively change the view of the spheres and triangles
Use the following key to action table to enable the user to change the view:
  • a and d — translate view left and right along view X
  • w and — translate view forward and backward along view Z
  • and e — translate view up and down along view Y
  • A and D — rotate view left and right around view Y (yaw)
  • W and — rotate view forward and backward around view X (pitch)
  • and E — rotate selection (counter-)clockwise around view Z (roll)
  • escape — undo all view changes; restore default view
To implement these changes you will need to change the eye, lookAt and lookUp vectors used to form your viewing transform.

Part 5: Interactively transform the spheres and triangles
Use the following key to action table to enable the user to transform your spheres and triangles:
  • left and right — select and highlight the next/previous triangle set (previous off)
  • up and down — select and highlight the next/previous sphere (previous off)
  • space — deselect and turn off highlight
  • k and ; — translate selection left and right along view X
  • o and l — translate selection forward and backward along view Z
  • i and p — translate selection up and down along view Y
  • K and : — rotate selection left and right around view Y (yaw)
  • O and — rotate selection forward and backward around view X (pitch)
  • and P — rotate selection clockwise and counterclockwise around view Z (roll)
  • backspace — undo all sphere and triangle transformations
A triangle set is one entry in the input triangle array. To highlight, set the selection's ambient and diffuse reflectivity to (0.5,0.5,0), specular to (0,0,0). To turn highlighting off, use normal lighting again. You will have to associate a transform matrix with each sphere and triangle to maintain state, and apply this transform in your vertex shaders. glMatrix will also be helpful here.

The extra credit components we suggest for this assignment are:
  • 1% arbitrarily sized viewports
  • 1% off-axis and rectangular projections
  • 2% multiple lights at arbitrary locations
  • 3% improved procedural sphere sampling
  • 5% smooth shading with vertex normals
Other extra credit is possible with instructor approval. You must note any extra credit in your file, otherwise you will likely not receive credit for it.

Extra credit: Arbitrarily sized viewports 
Accept a new square canvas (viewport) width/height through your UI. Size your canvas to match.

Extra credit: Support off-axis and rectangular projections 
Accept new window parameters in viewing coordinates through your UI (left, right, top, bottom). Adjust your projection matrix to this new window, and render the scene.

Extra credit: Multiple and arbitrarily located lights
Read in an additional lights.json file that contains an array of objects describing light location and color. Note that these lights will have distinct ambient, diffuse and specular colors. Render the scene with all of these lights. You can find an example lights.json file here. Assume that the input lights file will always reside at this URL when you turn in your code.

Extra credit: Improved procedural sphere sampling
Most sphere triangulations use the latitude/longitude parameterization, which oversamples the poles and alters topology around them (triangles vs quads), creating rendering artifacts. An alternative is to begin with a 20-sided icosahedron (one of the Platonic solids), recursively subdivide each triangle a few times to increase sampling resolution, and project all the new vertices onto the sphere containing the icosahedron. There are many triangle subdivision schemes, but a nice one for our purposes is Loop subdivision, which turns each triangle into four triangles by placing a new vertex at the midpoint of each edge.

Extra credit: Smooth shading with vertex normals 
Using only triangle normals, your spheres and other curved shapes will look disappointingly faceted. To represent curvature more accurately, you need vertex normals. As you generate spheres, create vertex normals as we did in your previous assignment: subtract the sphere center from each vertex. When you read in triangles, check for vertices in the input file. As you apply the composited modeling, viewing and projection matrices, make sure you apply them to your normals as well (had we used non-uniform scaling in this assignment, you would have to apply the inverse transpose of the composite). During lighting, use these normals rather than the face normal. The rasterizer will interpolate them for you.