Lab 02: Green Mountain SunsetGoalsBy the end of this lab, you will:
|
In this lab, you will start writing your own ray tracer. The objects in our scene will be defined in 3d, but we will mostly be rendering 2d-like scenes. We'll make our scenes look more 3d-like when we talk about shading techniques next week.
Please navigate to our replit
Team and open the assignment. Please find someone new to work with and create your group (only one person should create the group).
When you click the "Run" button, you should see a sunset-like background which transitions from pink (top) to blue at the bottom:
All of the code you will write will be in the sunset.js
file which contains a few class definitions. In particular, there are class definitions for a Ray
, Sphere
, Triangle
and the SunsetRenderer
class.
Note that the SunsetRenderer
takes in (1) the canvasId
(string) of the canvas in which we would like to render our scene, (2) the vertical field-of-view (fov
), as well as the objects in the scene. The first object is an instance of the Sphere
class which represents the sun. Next, there is an array of Triangle
objects which has a length of 3, for the three triangles representing the Green Mountains.
The SunsetRenderer
class saves the incoming information (fov
, canvas
, sun
and mountains
), which is then used in the render
method to render the scene. Your job primarily consists of modifying the render
method as well as the intersect
method of the Sphere
and Triangle
classes.
Note that there is already a loop over the pixels in the scene in the SunsetRenderer
render
method. The relative y-coordinate is used as the interpolation variable between blue and pink to define the initial background sky color.
Please review the notes and exercise from this week on how to create rays from a camera that pass through a particular pixel. Create a ray within the body of the nested for-loop (i.e. for each pixel). You should use the fov
as well as the image (or canvas) dimensions (and aspect ratio). You can use
Please complete the Sphere
intersect
method to detect intersections between the ray you compute in Part 1 and the sun. The sun is centered at
const cSun = vec3.fromValues(1.0, 0.894, 0.71);
When the ray intersects the sun, please set the pixel color to cSun
, and your image should look similar to the following picture:
Now complete the Triangle
intersect
method to detect intersections between a ray and a single triangle. Remember to check that all three barycentric coordinates are in the valid range of [0, 1]! Then, set the pixel color according to the closest intersection point (minimum ray cMtn1
and cMtn2
, already defined for you right after the definition of cSky
. The first and third triangles have a color of cMtn1
and the second triangle (this.mountains[1]
of the SunsetRenderer
class) has a color of cMtn2
.
Once this is complete, your image should look similar to the image at the top-right of this lab description. It won't look exactly the same since I changed some parameters after creating that picture, but it should be close. Feel free to adjust the triangle points in the index.html
file if you like (but please make sure the same order of the mountains is preserved).
glMatrix
alert!glMatrix
doesn't allow you to pass two indices (i.e. row and column) when accessing elements in a matrix - there is only one index. glMatrix
actually stores matrices in column-major order (see this picture) in a single 1d array, which means that for a 3x3 matrix like this:
the corresponding code to represent this matrix using glMatrix
would be:
let M = mat3.create();
M[0] = a;
M[1] = d;
M[2] = g;
M[3] = b;
M[4] = e;
M[5] = h;
M[6] = c;
M[7] = f;
M[8] = i;
In other words, think about going one column at a time when indexing the mat3
(as a 1d array) to access the elements.
Remember the 0.5 embedded in the equations for Math.random()
to generate random numbers between 0 and 1. This will now sample each pixel at a random point within the pixel instead of the center. The objects in your scene should look pretty rough with a single sample. Next, add a loop (nested within the i
and j
loops for each pixel) to send several random rays within each pixel. The final color you assign to the pixel should be the average of all the colors you compute with your random samples - here is a description of this algorithm:
1. for each pixel:
a. set color = (0, 0, 0) (this will be the variable we use for the final color)
b. for some # samples (spp):
i. cast a ray through this pixel (at a random sample location)
ii. compute the color from this sample
iii. add the sample color to the final color
c. divide the final color by the # of samples (to compute the average)
d. set pixel color to the final color
You should start to see the edges of the mountains look smoother at higher spp. Notice there is a console.log
message at the end of the render function which reports the elapsed time to render the scene (in milliseconds) and saves this in the elapsed
variable. Please calculate the framerate (in FPS), and complete the table in the questions.md
file with the framerate for 1spp, 4spp, 16spp and 32spp.
You can open a tab on the right of your repl
to preview the Markdown. Here is some info on what you can do with Markdown in replit
:
https://docs.replit.com/tutorials/replit/markdown
This part involves a theoretical question and can be completed at any point while working on the lab.
In the implementation for this lab, we set
And the ray direction is
Please show that
Please enter your derivation in the questions.md
file in your repl
.
Unfortunately, math equations are not supported in replit
's Markdown, but you can always take a picture of your equations and upload the picture to your repl
. Alternatively, you can create a .draw
file to draw your equations in an Excalidraw whiteboard.
The initial submission for the lab is due on Wednesday 09/27 at 11:59pm EDT. I will then provide feedback within 1 week so you can edit your submission.
When you and your partner are ready, please submit the assignment on replit
. I will then make comments (directly on your repl
) and enter your current grade status at the top of the index.html
file.
Please also remember to submit your reflection for this week in the Google Form below.
© Philip Claude Caplan, 2023 (Last updated: 2023-09-21)