COMP 3490 Assignment 1: Drawing on the Raster
Assignment 1: Drawing on the Raster
You will implement successive stages of the pipeline for drawing
and shading points, lines, triangles, and more complex shapes on a
raster. You have been provided with sample code that provides you
with a raw raster: you will achieve your results only by placing pixels
on this raster, and cannot use any additional drawing commands.
Do Not use math or vector libraries, etc., without checking. I used
Math.pow, and sqrt
This assignment is large, but modular, which enables you to get a
reasonable grade even if you struggle with some components.
You can get really lost and stuck on this assignment. To help you…
- I provided a file sketch and outline, so you’re not worrying about project design, data flow, etc.
as much. My design isn’t perfect, but it works. Focus on the graphics stuff instead. If you haven’t
downloaded it yet, do so now and study it. The structure works so it’s not advised to change it. - Pay attention to the hotkeys I built in, and the global flags they set. You need to use those to
make your program more flexible. DO NOT CHANGE the hotkeys, as the marker will use them to
test your program. - I strongly recommend you test everything as you go with known inputs and outputs. When not
possible, consider how to test graphically. For example, how could you test winding of your
triangles? Maybe using colors or sizes for vertices? Etc.
Marking
Marking for each section will be given below. Each section lists how to earn marks, but that whole
section will be scaled by the weight noted in the title. All code must work in the current version of
processing. Code that does not compile, does not run, or crashes regularly making it difficult to mark,
will receive a grade of 0. This assignment is not marked linearly in proportion to work. The last %, for
that A+, is really quite hard! The late policy is that late assignments will receive a grade of 0.
The quality and content of your code will also be marked. There are no hard and fast rules, but basic
programming quality such as good variable names and self documenting code, no using magic numbers
(literal numbers that are confusing – name them as a constant), reasonably elegant solutions, etc., will
impact your grade.
libJim
I have provided some functions that you can use and should not change; these are in libJim. They are
either explained below or inline in the file.
Task: Drawing Dots on the Raster using a Parametric Function (10%)
This task is to help you get used to working with the raster, and with parametric functions. You will draw
a Trefoil Knot using the standard parametric equations (https://en.wikipedia.org/wiki...),
deriving x, y, and z coordinates for t from 0..2PI. Play with how many steps you iterate to see how it
impacts the results. WARNING: do not accumulate floats in a for loop (almost universally a bad idea).
Use integers in your for loop and calculate the t value from those, to avoid error accumulation.
COMP 3490 Assignment 1: Drawing on the Raster
The raster in processing is 2D, with 0,0 at the top left and
width-1,height1 at the bottom right (but we do not use this).
Instead libJim gives you setPixel and setColor commands.
Look at them closely. You see that you set a colour that the
system remembers, and setPixel makes 0,0 be the center of
the screen, with the y axis increasing upward.
As this is a 2D raster, what do you do with the z coordinate?
At first you can ignore it. However, once you get it working
with x and y, encode z somehow into the colour (e.g., as
shown) to visualize it. (4 marks for shape, 2 for color)
Task: Implement Bresenham’s Line
algorithm (25%)
Implement the bresLine function stub provided, by only placing points on the raster.
HINT: note that I provided a line test function, as one of the standard modes,
which draws all 8 directions and plots it next to a ground truth. When your line
works, you’ll see something like on the right. Note the offset between the two
versions, that’s on purpose. (16 marks, 2 for each quadrant)
Task: Tesselate a Cube (25%)
In graphics we often make shapes up from triangles because of their nice properties. So if we can solve
how to draw and fill a triangle, then we can draw any shape that is made up of triangles very easily.
Since “tessellation” means to cover something with another shape, in this case, we need to generate
triangles that approximately cover a cube.
Now we start to hit the common challenge outlined in the lectures: coordinate systems. In this step, you
will be working in several coordinate systems simultaneously and it can be very confusing. First you will
generate 3D points with x, y and z values. Then (check the sample code), you will copy those points and
rotate them so now you have a rotated system of dots (this code given to you). However, how do we
draw 3D points on the screen? We need to do something with the z, a problem solved by “projection”.
We could just ignore the z coordinate (called orthographic projection), but this looks quite strange.
libJim has provided a function that you can use to project a 3D point into 2D one more naturally. Then,
when shading, you may still need the original 3D information to choose colours. It’s confusing!
Generate triangles (3D) -> manipulate triangles (3D) -> project final 3D points into 2D triangles for
screen -> use 2D projected coordinates for back face culling and filling, and 3D information for lighting.
I recommend doing two steps. First generate the points
around the cube that will serve as the triangle corners.
AGAIN: don’t accumulate floats / use floats in your for
loops. Use integers. Store the resulting points in some
sort of data structure (I used a single multi-dimensional
array). At this point you can use temporary debug code
to draw your points for debugging. You can draw ignoring
the z coordinate (left), or use the projection function to
incorporate it (right). These are the same points but the z coordinate is handled differently.
COMP 3490 Assignment 1: Drawing on the Raster
Then, in a second loop go through your points and “stitch”
the triangles over it. This simplifies the problem by
enabling you to test and debug each stage separately.
Note that each set of 4 points can have two triangles.
Populate a triangle array with all the triangles, noting that
you only need to do this once, at the start of your
program. Then in your triangle draw code, project the
points and use your line algorithm to draw the triangle
outlines. I’d start with one cube face at a time and test that.
At this point you should be able to display and have rotation working. You do not need to understand
the math of the rotation (we’ll learn that later), but you should understand what it’s doing to your data
and how it fits into the flow. The images to the right show the wireframe cubes. They look like a mess
because you can see through to all sides. (5 marks tesselation. Rotation must work for testing)
Implement back-face culling using a single cross product
test. Be careful of triangle winding! Think up a way to
test, e.g., only drawing a few triangles, using colours or
point sizes for the vertices, etc. Wind CCW. Hint: some
degenerate triangles will not have size 0 due to floating
point precision, so instead cull anything with size <~ 1
pixel. The result is shown on the right. (2 marks)
Note about pixel-perfect results: depending on your bresenham’s line algorithm,
you may find little extra pixels or small 1-pixel holes in the corners, double lines
where you’re drawing two triangles, etc. This can be tricky to get just right unless
you move to an all-integer solution. If it’s only these errors, and not egregious
ones, just leave it.
Make sure it all works with more divisions! Try now with more divisions!
Task: Scan-Line Fill (25%)
Use the scan line algorithm (and point-intriangle
test) to fill the triangles. Start with
FLAT shading (a constant colour). If you
remove the outline, it should just look like
a silhouette. No seams. (5 marks)
A note on pixel-perfect: since the point in
triangle test is floating point and the line
algorithm uses integers early, you will have
mismatch on some edges between the fill and the
outline (see inset). In production you’d fix this, but
don’t bother for this assignment.
Next implement barycentric shading: simply
visualize the barycentric coordinates linking by
making r=u, g=v, b=w. Notice how the colours
indicate winding. (3 marks)
COMP 3490 Assignment 1: Drawing on the Raster
Task: Phong and Gouraud (15%)
Finally, you will implement more advanced shading and lighting models.
Implement Phong lighting. First, do face-level lighting: calculate the face normal (using the cross
product), and Phong colour for the whole face. NOTE normals must be calculated on the final, rotated
triangles, not the original points. Don’t pre-calculate, you can’t transform normals directly. (3 marks).
Next, do vertex-level lighting. Calculate the normal for each vertex (note that on the flat surface of a
cube, this is the same as the center). Calculate Phong at each vertex, and average for the face color.
You’ll get slightly better results than face-level Phong, as shown, but more obvious when animating. (2
marks)
Since you have already solved barycentric coordinates, you have essentially implemented Gouraud
shading. Instead of using u, v, w directly in the r, g and b channels, blend the colours from the three
triangle vertices using u, v, and w, where c = cv1u + cv2v+ cv3*w (cvn is colour at vertice n). Use with
Phong at each vertex. (2 marks)
Finally, we have Phong shading (* check the notes. This is where you interpolate the normals between
the vectors, using barycentric coordinates, and then calculate Phong lighting at each fragment). (3
marks)
PRO TIP: shading and lighting is really tricky. Visualize anything you can to help
yourself debug. One common thing is to visualize the normal. Here is my
implementation, where I draw normal 20px long by adding the normal to the start
point. For the face normal, I calculate the center location by averaging the points.
Face-level phong Vertex-level Phong,
averaged
Per-vertex Phong with
Gauraud shading
Notice the results are despite
the sparse geometry
Phong Shading