In this homework, the process was straightforward. Building from the previous homework (Embree skeleton code), we implemented a simple path tracer first in the file PathTracerIntegrator.cpp. Of course, we included all the necessary commands needed to run the test scenes (next event estimation, samples per pixel, and russian roulette, these are relatively simple flags). Our path tracer is recursive. Initially it starts with the hit material's emission color (if there is no hit, it is colored black). Afterwards we calculate the direct lighting if next event estimation is enabled (very similar to the implementation in homework 2). If Russian Roulette is enabled, then we would also eliminate the ray here if it falls under the calculated probability, which prevents introducing bias to our render. Then we calculate the indirect lighting using Monte Carlo's rendering equation. Note that we uniformly sample the hemisphere (not cosine weights) and we do not use importance sampling. For the shading we implemented Blinn-Phong shading.
We also had to modify RenderPool.cpp to add randomness to the ray's origin from the pixel; this added anti-aliasing to our final render.
We chose to not optimize our renderer further because the renders already took very little time for the test scenes. The most expensive one (dragon.test) took around 10 seconds to render. Doing any optimizations would only make the homework more complicated.
Our biggest challenge was actually implementing the rendering equation correctly. The formula in the homework description and the lecture was very confusing, with little to no detail on which function actually did. I had to look back on previous homeworks to remind myself how the BRDF function was calculated, or how to get the reflectance vector. With a lot of vector operations came a lot of bugs that put me off of completing the tests for a while.
cornellNEE.test
cornellRR.test
cornellSimple.test
dragon.test
cornellSimple.test (at 1 spp)