HW5 · Meshes, texture placement, and a lit shader

Henri Gouraud's smooth shading, interpolating vertex colors across a polygon, dates from 1971.Gouraud, Continuous Shading of Curved Surfaces, IEEE Transactions on Computers, 1971
Out Thursday November 5 · due Wednesday November 11, 11:59 PM on Canvas · 25 points · Unity or WebGL · hub · schedule · syllabus · all homework
Read before this homework: Polygonal Meshes §2, a grid from a formula · §5, face and vertex normals · Texture Mapping §4, placement · Local Illumination §2 to §4 · Unity Shaders §7, lighting in the shader · Shaders in GLSL (three.js) §6 and §7, lighting, the normal and the output colour

What you build

The surface week in one homework: the 2 × 2 grid of the mesh demo as two arrays, its face and vertex normals after the center is lifted, the texture placement matrix at the demo's settings, and the Phong and Blinn terms at the illumination demo's marked point, first as a function and then as the fragment shader that lights a sphere.

JavaScriptC#What it computes
gridMeshGridMesh(n + 1)² positions on XZ spanning [−half, half] (vertex row · (n + 1) + col; col along +x, row along +z), the center vertex lifted to y = lift; 2n² triangles, per quad (v00, v10, v01) then (v01, v10, v11).
faceNormalFaceNormal(b − a) × (c − a), not normalized.
vertexNormalsVertexNormalsPer vertex, the normalized sum of the unnormalized normals of the faces touching it.
uvPlacementUvPlacementThe column-major 3 × 3 that translates by (offU, offV) after rotating by rot and scaling by tile about (0.5, 0.5).
phongPhongN·L, R·V, H·N, diffuse = max(0, N·L), specular = max(0, R·V)shine, blinn = max(0, H·N)shine (both specular terms 0 when N·L ≤ 0).
FRAGMENT_SHADERHW05Lit.shaderka kd + kd max(N·L, 0) + ks · specular, per pixel (graded by eye: the lit sphere must show a highlight that follows the light).

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
1gridMesh(2, 1.5, 0.4): the eight index triples((0, 3, 1), (1, 3, 4), (1, 4, 2), (2, 4, 5), (3, 6, 4), (4, 6, 7), (4, 7, 5), (5, 7, 8))exact12
2gridMesh: position of the lifted center vertex (vertex 4 when n = 2)(0, 0.4, 0)0.0000014
3faceNormal of triangle 1 (vertices 1, 3, 4 when n = 2), unnormalized(-0.6, 2.25, -0.6)0.00110
4vertexNormals: vertex 1(-0.0872, 0.9808, -0.1744)0.00112
5vertexNormals: the center vertex(0, 1, 0)0.0016
6uvPlacement at the defaults (0, 0, 0°, tile 2): 9 entries(2, 0, 0, 0, 2, 0, -0.5, -0.5, 1)0.00110
7uvPlacement(0.25, 0, 45°, 2): 9 entries(1.4142, -1.4142, 0, 1.4142, 1.4142, 0, -0.6642, 0.5, 1)0.00114
8phong at the marked point: N·L and diffuse(0.9883, 0.9883)0.00110
9phong: R·V and the Phong specular (R·V)^30(0.8788, 0.0208)0.00112
10phong: H·N and the Blinn specular (H·N)^30(0.9689, 0.3873)0.00110
The published inputs
{
 "grid": {
  "n": 2,
  "half": 1.5,
  "lift": 0.4
 },
 "uvDefaults": [ 0, 0, 0, 2 ],
 "uvAll": [ 0.25, 0, 45, 2 ],
 "shade": {
  "N": [ 0.57735, 0.57735, 0.57735 ],
  "P": [ 0.692820323027551, 0.692820323027551, 0.692820323027551 ],
  "light": [ 1.8371173070873839, 1.4999999999999998, 1.8371173070873834 ],
  "eye": [ 3, 3, 6 ],
  "shine": 30
 }
}

Implement and replace

Build each function from primitives (dot, cross, normalize, component access, sin, cos, pow.) 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)uvMat3 from xform.js; THREE.PlaneGeometry, computeVertexNormals, Matrix3.setUvTransform, Texture.repeat / offset / rotation; three.js lighting materials for the sphere.
Unity (C#)Mesh.RecalculateNormals; the built-in Plane for the grid; Material.mainTextureScale / mainTextureOffset; the Standard shader for the sphere.

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=hw05.
  3. Edit lib/skeletons/hw05.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/hw05/unity/ into Assets/HW05/.
  3. Create an empty GameObject, add the Checks component (namespace CSS551.HW05), and press Play: the Console lists every check with your value and the expected one.
  4. Edit HW05.cs and the fragment program in HW05Lit.shader; 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.