Sometimes icy heart just needs warm smile.

— Braum League of Legends

Path Tracer

Jul 2025

Concept

The goal of my project was to deepen my understanding of physically based rendering by implementing and exploring path tracing and some related, visual improvement features to render an image which seemed cool. My project is a basic, unidirectional path tracer with added support for some additional materials and camera settings. As it is a path tracer, it is not intended to be interactive or to run real-time but rather to generate pretty pictures. While I did not do as much as I wanted to, I learned a lot and look forward to furthering my understanding on my own time in the future. As this was an assignment for a class, I can’t in good faith share the code for the sake of academic integrity. However, I will mention that this project landed me second place, which can be viewed in the provided link at the top of the page.

Functionality

I added a number of feature flags to the code so that I could turn functionality on or off as desired. This was mainly to make it easier for markers to tell what I had done, but now it useful to show off the different bits of functionality here. I will mention that these demo scenes include some things I threw together in Blender quickly before I understood how to use it, so you may notice some silly issues (e.g. bad vertex normals resulting in over-faceting), but please try to overlook them and focus on the features themselves.

Path Tracing

The goal here was to implement unidirectional path tracing with uniform hemisphere sampling. This one is kind of weird to show as it’s just “the whole project” basically. To try to show this properly, I’m using the default Cornell Box that we were given, with the only change to the scene being the addition of a plain area light. For the initial scene, a bunch of the enhancements are turned off to try to simulate non-path tracing. This is not going to be perfect, but it should serve to show how far we’ve come. Path Tracing Baseline

Now, we enable a bunch of the stuff that we did for path tracing. This should serve to show the softer shadows, the colouring reflecting between Lambertian surfaces, etc. that comes with the improved methods. Hopefully this is enough as a comparison. Path Tracing Activated

Multiple Importance Sampling

I wanted to add multiple importance sampling in for more efficient sampling. First of all, we need to not use it for comparison. Here’s what we see if we don’t do cosine weighted hemisphere sampling for Lambertian surfaces (just random in hemisphere), and also don’t use MIS for the lights. No Importance Sampling

Now, add in cosign weighted hemisphere sampling for Lambertian surfaces. Importance Sampling

Finally, the last piece of the puzzle is added by importance sampling the lights as well, and then mixing it all together for MIS. Multiple Importance Sampling

Textured Area Lights

Points lights can only go so far, so area lights are the way to go. Normal, and textured as well for more fun. First, just use a point light. Point Lights

Now actually give the area light emission instead. Area Light

And we can also give the area light its own texture with which to emit. This texture is just a half-and-half coloured square, but it serves its demonstrative purpose. Textured Area Light

Microfacet Materials

We already had Lambertian materials, as well as dielectrics (reflective / metal) and glass. Implementing microfacet materials with the GGX (Trowbridge and Reitz) distribution would allow for more interesting scenes. Here I’m displaying an array of objects with microfacet materials. These materials differ only in their roughness, where they get more rough as we go to the right. Microfacet Materials

Bump Mapping

We can use bump mapping to add some fake details with the light. While this won’t hold up when looking at glancing angles, it can still look neat. Before applying the bump map, we get the standard red sphere. No Bump Mapping

Then, apply the hastily-made bump map I made in Paint.net with noise and a circle. Bump Map

I added a parameter to scale the bump map influence, we can make the bump map go harder. Bump Map Harder

Purely for comparison, here’s what it would look like if the texture were used as a standard texture rather than as a bump map. objective6-textured

Depth of Field

To be closer to a normal camera, imperfections and all, I implemented depth of field with a thin lens approximation. Without depth of field, this shows all objects in focus. No Depth of Field

Now, turn on depth of field and focus on the closest object. Depth of Field Close

We can also make the objects out of focus appear blurrier by increasing the size of the aperture. I didn’t want it to get too disgusting so just moderately bumping it up so it is still distinguishable. Depth of Field Close Blurrier

Then we can move the focus distance as well. This shows it focussing on the middle objects. Depth of Field Middle

Finally, focus on the farthest objects, just for the sake of completeness. Depth of Field Far

Motion Blur

Another camera effect is motion blur. One way to do this is to blur the frames together, such that it doesn’t matter if objects are moving or the camera is moving, it all blurs. Another way is to track the positions of the objects at the start and end of frames, and then sample across time as well as space so that the moving objects are blurred, independant of camera motion. The latter seemed more interesting so that’s what I tried. We want to see what it looks like without motion blur first, so let’s look at the 14th frame of the capture of a ball falling.
No Motion Blur Frame

And now show it in motion.
No Motion Blur GIF

Now, with motion blur, we can once again look at the 14th frame. Motion Blur Frame

And once again in motion. Motion Blur GIF

Final Scene

Putting it all together into a final scene which I created in a panic in Blender without knowing how to use the software with a deadline looming, we get the end result. final

The depth of field makes it a little difficult to tell what’s going on, so we can turn it off to reduce the blurry mess.
final-no-dof

And here is it in motion, but using a much lower sample count for reasonable render times (1000 samples vs 8192 of the earlier images).
objective8-blur

Credit

Credit where credit is due. I am no artist, so artistic assets are all taken from other places. This section serves to document these borrowings.