<- back
hw09 help hours | codebase | docs | notes | glow

🚨 please pull a fresh copy of the codebase before starting this homework! 🍏 if this homework runs slow, please reduce your window size to speed things up 🗣️ you are highly encouraged to collaborate on homework provided you follow the spirit of the 50 ft rule 👥 additionally, for this lab you may optionally choose to work with a partner 🦍 this homework is tough 📺 sample solution
goals. - get a first taste of ray tracing - get a first taste of ray marching distance shaders
optional. math review here is a quick linear algebra crash course
lecture summary. a ray a ray is parameterized by the equation $\mathbf{p}(t) = \mathbf{o} + t\mathbf{d},$ • $\mathbf{o}$ is the ray's origin (e.g, the camera position/origin) • $\mathbf{d}$ is a ray's direction (a vector pointing from, e.g., the camera origin to a particular pixel) • $t$ is "distance," i.e. how far we've travelled along the ray; note that for a ray, $t > 0$
lecture summary. basic ray tracing for each given pixel, a primary ray is shot (cast, traced, etc.) from the camera origin toward the pixel - please see the lecture slides for help calculating the ray's direction $\mathbf{d}$ in code if the ray hits the mesh, then a shadow ray is shot from the position of the first hit to the position of the light source - if the shadow ray makes it to the light source without hitting anything else, then the surface patch at the hit position is lit - otherwise it is in shadow lit surface patches get the full Blinn-Phong lighting model surface patches in shadow get only the ambient term - for this assignment, the ambient color should be something like 0.4 * color, where color is the barycentric interpolation of the hit triangle's vertex colors (NOT, e.g., vec3(0.4) like we used in the shader assignment) -- note: everything is in world coordinates, so $\mathbf{color} = \alpha{\mathbf{color}_a} + \beta{\mathbf{color}_b} + \gamma{\mathbf{color}_c}$ is perfectly correct
lecture summary. ray-triangle intersection Consider ray with origin $\mathbf{o}$ and direction $\mathbf{d}$. Let's intersect the ray with some triangle $(\mathbf{a}, \mathbf{b}, \mathbf{c})$. For simplicity, say all these quantities are in world coordinates. Call the (possible) intersection point $\mathbf{p}$ and get pumped. Our approach is to express $\mathbf{p}$ in two different ways and set them equal. First, we can write down the definition of a ray $$ \begin{cases} \mathbf{p} = \mathbf{o} + t\mathbf{d} \end{cases},$$and the condition for the $\mathbf{p}$ being in front of the camera (not behind it) $$\begin{cases} t > 0 \end{cases}.$$Second, we can write down the definition of barycentric coordinates $$\begin{cases} \mathbf{p} = \alpha\mathbf{a} + \beta\mathbf{b} + \gamma\mathbf{c}\\ \alpha + \beta + \gamma = 1,\end{cases}$$and the condition for $\mathbf{p}$ being inside the triangle $$\begin{cases} \alpha,\beta,\gamma > 0 \end{cases}.$$Equating the different equations for $\mathbf{p}$ gives us the following system of equations $$\begin{cases} \mathbf{o} + t\mathbf{d} = \alpha\mathbf{a} + \beta\mathbf{b} + \gamma\mathbf{c}\\ \alpha + \beta + \gamma = 1.\end{cases}$$Taking on both conditions (in front of camera; inside of triangle) gives us the condition for a "hit" $$\begin{cases} \alpha,\beta,\gamma,t > 0.\end{cases}$$ All that remains is to find $\alpha,\beta,\gamma,t$. Rearranging the system of equations yields $$\begin{cases} \alpha\mathbf{a} + \beta\mathbf{b} + \gamma\mathbf{c} - t\mathbf{d} = \mathbf{o}\\ \alpha + \beta + \gamma = 1 \end{cases}. \tag{1}$$ We will solve Equation 1 for $\alpha,\beta,\gamma,t.$ For a change, let's bash with a matrix solve :) Using our handy dandy linear algebra trick, the first equation in Equation 1 becomes $$\begin{bmatrix} \mathbf{a} & \mathbf{b} & \mathbf{c} & -\mathbf{d}\end{bmatrix} \begin{bmatrix} \alpha \\ \beta \\ \gamma \\ t \end{bmatrix} = \begin{bmatrix} \mathbf{o} \end{bmatrix},$$onto which we tack on the second equation to yield our final system $$\begin{bmatrix} \mathbf{a} & \mathbf{b} & \mathbf{c} & -\mathbf{d} \\ 1 & 1 & 1 & 0 \end{bmatrix} \begin{bmatrix} \alpha \\ \beta \\ \gamma \\ t \end{bmatrix} = \begin{bmatrix} \mathbf{o} \\ 1 \end{bmatrix}.$$You are the One, Neo
a. implement a software raytracer - this hw is written to follow a similar structure to the rasterization homework :) - initially, we will be working entirely inside of the raytrace(...) function -- eventually, you will want to add your own function immediately above it that casts a single ray i. set up the rays properly - add a checkbox to draw them using eso_begin(PV_for_debug_drawing_rays, SOUP_LINES, 1.0) -- once you're confident the rays are set up right, you're welcome to delete this functionality
(hint / spoilers) drawing rays with eso Here's a way to do it with only a single call to eso_begin(...) and eso_end(...). vec3 o = ... eso_begin(PV_for_debug_drawing_rays, SOUP_LINES); eso_color(monokai.white); for (int i = 0; i < side_length_in_pixels; ++i) { for (int j = 0; j < side_length_in_pixels; ++j) { vec3 d = ... eso_vertex(o); eso_vertex(o + d); } } eso_end();
ii. draw the triangles in the right place in a single color (say, blue)
(readme) sample code to iterate over the meshfor (int tri = 0; tri < mesh->num_triangles; ++tri) { vec3 a = mesh->vertex_positions[mesh->triangle_indices[tri][0]]; vec3 b = mesh->vertex_positions[mesh->triangle_indices[tri][1]]; vec3 c = mesh->vertex_positions[mesh->triangle_indices[tri][2]]; ... }
iii. draw the triangles in the right color (no shadows; no lighting) iv. get overlap correct if you haven't already (i.e., color the pixel according to its ray's first (minimum $t$) hit) v. add shadows - to get shadows up and running as quickly as possible, i would fornow make the color be (0.5 * color) if the pixel is in shadow -- a pixel is in shadow if its shadow raw hits a triangle OR its normal is facing away from the light --- (two vectors face away from each other if their dot product is negative) --- the "its normal is facing away from the light" check will no longer being necessary if you properly implement lighting in vi. - your code should NOT contain large amounts of repetition (i.e., no copy and pasting 50 lines) -- first, make it work; then, let a function (and a struct) spring forth organically! 🌱
(hint / spoilers) my ray casting APIstruct CastRayHit { real t; // t at the hit point; recall ray equation is p(t) = o + (t * d) int tri; // index of triangle that was hit; -1 if no triangles were hit bool hit_any_triangles() { return (tri != -1); } vec3 p; // position of hitpoint vec3 n; // normal at hitpoint vec3 color; // color at hitpoint // barycentric coordinates of hit real alpha; real beta; real gamma; }; CastRayHit cast_ray(IndexedTriangleMesh3D *mesh, vec3 o, vec3 d) { CastRayHit hit = {}; hit.t = INFINITY; hit.tri = -1; for (int tri = 0; tri < mesh->num_triangles; ++tri) { ... } return hit; }
vi. add Blinn-Phong lighting (or Phong, or something vaguely similar) determine the pixel color similarly to your fragment shader from hw6c, with this modification: - lit surface patches get the full lighting model - surface patches in shadow get only the ambient term note: we are NOT using a shader this time; all on the CPU (vroom vroom 🐢) :) 🔆. make some of the triangles perfectly-reflective mirrors - e.g., if ((tri == mesh->num_triangles - 2) || (tri == mesh->num_triangles - 1)) { ... } -- (these are the floor for the teapot scene) - you'll need to pick a color for the sky
b. (Creative Coding) ray march something nice - initially, we will be working entirely inside of the march(...) function inside of hw9b.frag -- i put the shader in a separate file to make your IDE happy :) - references! -- you may copy and paste code from https://iquilezles.org/articles/distfunctions/. -- optional reading: https://michaelwalczyk.com/blog-ray-marching.html -- you may browse shadertoy for inspiration, but you may _not_ copy and paste code (the 50 ft rule applies) --- if you are heavily inspired by a shader, please link it in your glow comment - please include a one-two sentence writeup explaining what you did in your glow comment 😎. add blinn-phong lighting (or something similar) - you will need to google around for how to approximate the surface normal using finite differences ohwowsofun :D