HW4 · Viewing and rasterization

The z-buffer was described in 1974, in Ed Catmull's Utah thesis and independently by Wolfgang Straßer in Berlin.Catmull, PhD thesis, University of Utah, 1974; Straßer, PhD thesis, TU Berlin, 1974
Out Thursday October 29 · due Wednesday November 4, 11:59 PM on Canvas · 25 points · Unity or WebGL · hub · schedule · syllabus · all homework
Read before this homework: Viewing §2, the view matrix · §5, the projection matrix · §8, the full chain · Rasterization §1, edge functions · §4, barycentric coordinates · Unity Shaders §4 · Shaders in GLSL (three.js) §4

What you build

The two matrices that turn a placed world into pixels, checked entry by entry against the text's numbers, then the whole chain for one vertex: model, view, projection, the divide, the viewport. Then the other half of the pipeline: which pixels a triangle covers, by three edge functions per pixel center. The runner renders the scene through your V and P (three.js is told not to compute its own) and marks where your chain puts the cube's corner.

JavaScriptC#What it computes
viewMatrixViewMatrixV with rows u, v, w and column 3 = −(u·eye, v·eye, w·eye); w = normalize(eye − at), u = normalize(up × w), v = w × u.
perspectiveMatrixPerspectiveMatrixThe OpenGL perspective matrix: f = 1 / tan(fovY/2); row 3 = (0, 0, −1, 0).
worldToPixelWorldToPixel(pixel x, pixel y, NDC depth) of an object point through M, V, P, the divide and the viewport; pixel y counts DOWN from the top-left.
edgeEdgeTwice the signed area of (a, b, p).
barycentricBarycentricThe three weights of p in the triangle, each an edge function over the triangle's own.
rasterizeRasterizeThe pixels (i, j) of a res × res grid over [0, 1]² whose center ((i + ½)/res, (j + ½)/res) has all three weights ≥ 0.

The numbers a correct build reproduces

Each row is one check, run on your functions with the published inputs below. The same table appears under the scene in the runner and in the Unity Console.

#CheckExpectedTolerancePoints
1viewMatrix: all 16 entries of V(0.8192, -0.1962, 0.539, 0, 0, 0.9397, 0.342, 0, -0.5736, -0.2802, 0.7698, 0, 0, -0.4698, -7.171, 1)0.00220
2perspectiveMatrix(45°, 16:9, 1, 8): all 16 entries(1.358, 0, 0, 0, 0, 2.4142, 0, 0, 0, 0, -1.2857, -1, 0, 0, -2.2857, 0)0.00215
3worldToPixel: object point (0.5, 0.5, 0.5) to pixel x, y and NDC depth(702.505, 320.864, 0.924)0.0520
4barycentric at the center of pixel (5, 6)(0.3052, 0.259, 0.4358)0.00212
5barycentric at the center of pixel (1, 9): outside, one weight negative(0.2992, -0.3887, 1.0894)0.0028
6rasterize at 12 × 12: number of covered pixels28exact15
7rasterize at 64 × 64: number of covered pixels846exact10
The published inputs
{
 "eye": [ 3.7729, 2.8941, 5.3883 ],
 "at": [ 0, 0.5, 0 ],
 "up": [ 0, 1, 0 ],
 "fov": 45,
 "width": 1280,
 "height": 720,
 "near": 1,
 "far": 8,
 "model": {
  "ry": 30,
  "t": [ 0, 0.5, 0 ]
 },
 "objectPoint": [ 0.5, 0.5, 0.5 ],
 "tri": [
  [ 0.242102, 0.143041 ],
  [ 0.876839, 0.478762 ],
  [ 0.361059, 0.858197 ] ],
 "res": 12,
 "pixelIn": [ 5, 6 ],
 "pixelOut": [ 1, 9 ]
}

Implement and replace

Build each function from primitives (dot, cross, normalize, matrix products, applying a matrix to a point, tan.) and use the engine's own helper, where one exists, only to check your result. These are off limits in your submission:

TrackOff limits
WebGL (JavaScript)lookAtBasis and perspective from xform.js; THREE.Matrix4.lookAt, makePerspective; camera.updateProjectionMatrix; Vector3.project.
Unity (C#)Matrix4x4.LookAt, Perspective, TRS, .inverse; Camera.worldToCameraMatrix, projectionMatrix, WorldToScreenPoint; GL.GetGPUProjectionMatrix.

Getting started

WebGL track.
  1. Get the homework starter repository (about 2 MB): git clone https://github.com/mgav-uwb/UWB-CSS-551-AU26-homework.git, or Code, then Download ZIP. It gains each homework the day it goes out; git pull fetches it.
  2. In its root folder run python3 -m http.server 8000 and open http://localhost:8000/homework/run.html?hw=hw04.
  3. Edit lib/skeletons/hw04.js, the only file you change, and reload: the Checks table under the scene compares your numbers with the ones below.

The unfilled skeleton runs on this site too, so you can see the page before you start. The setup, the blank page a file opened from disk gives, and how to read the Checks table are in WebGL and three.js for This Course.

Unity track.
  1. In Unity Hub, create a new project with the 3D (Built-In Render Pipeline) template in editor 6000.3.11f1.
  2. From the homework starter repository, copy the files in homework/hw04/unity/ into Assets/HW04/.
  3. Create an empty GameObject, add the Checks component (namespace CSS551.HW04), and press Play: the Console lists every check with your value and the expected one.
  4. Edit HW04.cs; the other files are given.

The Unity files compile against a stand-in for the UnityEngine API and pass their checks with the reference solution, but they are new this quarter and have not yet been opened in the Unity editor. If one does not compile in 6000.3.11f1, post the error on the Canvas board and use the WebGL track meanwhile.

Submitting and grading

Grading runs your functions twice: on the published inputs above and on a second set of inputs that is not published. A check earns its points only when your value is within its tolerance on both, so the numbers have to come from the math. The rubric score is the sum of the points earned, out of 100; it counts as 25 course points (the rubric score divided by 4). A submission that does not load or compile earns no check points. Name any collaborators and tools in the submission comment.

Late tokens. You have two for the quarter. Declare one in the submission comment to extend this homework by 48 hours without penalty. Without a token, late work is not accepted, and nothing is accepted after Friday, December 11.