Skip to the content.

Homework 1

Overview

This project aims to go through the basics of rasterization. Starting from the simplest of rasterization of single color triangles, to other options including supersampling, interpolating colors, and mipmaps for texture mapping. Other tasks include transformation operations, comparisons between different sampling methods, and a cool SVG edit.

One of the first takeaways I learned from this class is what aliasing and anti-aliasing is. As someone who grew up playing video games, the “Disable anti-aliasing” option would always be in the settings, but I never truly understood what it meant by that until taking this class, and doing this project.

Task 1

We are given that the first task can be completed simply by modifying the rasterize_triangle() function in rasterizer.cpp. I started by computing the bounding box of the triangle: using the minimum of the three x values as the left boundary value, the maximum of the three x values as the right boundary value, and similarly for top and bottom boundary values. Once I had all four boundary values, I simply used a nested for loop to iterate through all x and y pairings, representing all the possible locations of a pixel within the bounding box.

I wrote a separate function, inside(), that would, given an x, y point coordinate and the coordinates for the two endpoints of a triangle edge, return whether the point was inside the edge. For each iteration, I would call the inside function on this iteration’s x, y point 3 times, once for each triangle edge. If all three calls evaluated to true, then the point had passed the three-line test, and was thus inside the triangle. Since it was inside the triangle, I could simply call fill_pixel() on this point to color it as part of the triangle.

Since this algorithm literally checks every sample within the bounding box of the triangle, it is trivially no worse than an algorithm that checks each sample within the bounding box of the triangle.

basic/test4.svg

Task 2

In order to super sample, I modified the sample_buffer data structure by changing the size such that it would be width * height * sample_rate in order to “fake” a higher resolution picture. I then also edited resolve_to_framebuffer to make it such that we can get different shades of colors by averaging the colors of each sample and then moving it into the rgb_framebuffer_target, and finally edited rasterize_triangle by adding two nested loops to iterate through the samples for each pixel, which were evenly distributed. Furthermore, I no longer used fill_pixel, but instead, edited the sample_buffer directly.

Sample Rate: 1 Sample Rate: 4
Sample Rate: 9 Sample Rate: 16

Task 3

This is Mingy, the dapper dabber. I gave him a sick pair of shirt, and a pair of jorts. And, of course, he is dabbing.

Task 4

Barycentric coordinates is a coordinate system that allows us to interpolate between the vertices, and lets us obtain smooth varying values.

svg/basic/test7.svg Barycentric Coords Example

Task 5

Pixel sampling is when we iterate through samples within each pixel that is in the bounding box of the triangle, and calculate the alpha, beta, and gamma weights from the barycentric coordinates. From this, we can calculate a weighted sum of the texture coordinates for the current sample point.

Nearest Neighbor Sampling Rate: 1 Nearest Neighbor Sampling Rate: 16
Bilinear Interpolation Sampling Rate: 1 Bilinear Interpolation Sampling Rate: 16

The biggest difference between the two sampling methods is most clearly shown when the sampling rates are both 1. You can see that the nearest neighbor has many more islands, while the bilinear interpolation contains a smoother line, especially in the horizontal direction.

It is less noticable in the sampling rate of 16, which makes sense as a higher sampling rate would mean that each pixel would have to cover less of the texture map and would result in a very similar image to bilinear interpolation. This, however, would be more costly, as we are sampling 16 times more than the original sample rate.

Task 6

Level sampling is basically determining how much detail do we want based on the original texture by storing worse and worse qualities of the same image (each version being twice as small as the next). Then, we can use the texture file whose resolution would best approximate the sampling rate of the screen.

Supersampling almost always produced the best antialiasing results, but was more costly in both memory and speed due to the increase of points we have to check. Although Mimaps are also memory intensive due to having to store several images, because it is precomputed, the speed is much faster.

Supersampling consistently produces excellent antialiasing results, but comes at a significant tradeoff in both speed and memory usage due to the significant increase in sampling occurrences. Mipmaps (level sampling) require more memory in order to store the various resolution level texture images, but gain a boost in speed (from the precomputation) and antialiasing as a result. Bilinear interpolation is less efficient than nearest neighbor as a sampling technique, but the slower speed results in generally better antialiasing, as the process of interpolating neighboring sample points is very effective for removing jaggies and sharp artifacts.

Nearest Neighbor + 0th mip Bilinear Interpolation + 0th mip
Nearest Neighbor + nearest mip level Bilinear Interpolation + nearest mip level