Tim's Portfolio
Path Tracing
![](/static/img/pathtracing/blockball05.png)
How it works
Path tracing, like conventional computer rendering, draws 3D objects as seen by a virtual camera by finding where lines of sight from the camera intersect with nearby objects. Unlike conventional rendering, when a ray of light hits an obstacle, path tracing simulates multiple additional bouncing rays which contribute light to the original point that was hit. Path tracing is able to faithfully reproduce many real-world phenomena, such as global illumination, depth of field, caustics, and a large variety of material properties. The recursive nature of path tracing, as well as the large number of simulated rays per pixel that are needed for smooth images, can make a naive implementation of a path tracer quite slow.
My implementation of a path tracer is of the naive variety, and so it converges very slowly for scenes with very few, small, bright light sources (which unfortunately describes most natural scenes). Most of the images you'll see here are flooded with light and light-emitting surfaces, which converges more quickly and gives a delightfully other-wordly if not quite realistic look.
The simple representation of light rays bouncing off surfaces that path tracing uses makes it remarkably easy to implement a large number of pleasing optical effects with simple vector calculus, including
- Specular reflections
- Diffuse reflections
- Glossy reflections
- Refraction
- Caustics
- Depth of field
among others.
My pather tracer is designed to be fairly agnostic to the geometric representations of objects it's rendering, as long as one can find points of intersections with rays and surface normals. At the moment, rectangular prisms, spheres, triangles, and signed distance fields are implemented.
In natural scenes, most of the computation of a path tracer is wasted by naively gathering light rays from dark areas, without giving direct and indirect light sources the extra attention they deserve. Building a better path tracer requires a good understanding of efficient probabilistic sampling that still remains accurate (or "unbiased"). I may attempt this in the future. But in the meantime, here are some pretty pictures.
Source Code
The C++ implementation is available on GitHub.
Surface Materials
Whenever a ray hits a surface, the light that is seen along that ray is gathered from three different major sources:
- Light emitted by the surface itself, such as a light source or incandescing object
- Rays that bounce off the surface and hit other light sources, which is reflection
- Rays that pass through the surface before later leaving and hitting other light sources, which is refraction
Just about any physical material can be described by how it transmits, reflects, and refracts light according to where the material was hit, what angle it was hit at, and where other light sources are located relatively.
Specular (or shiny) surfaces reflect incoming rays perfectly, which creates a crisp and detailed reflection. Diffuse (or matte) surfaces will randomly bounce rays in many different directions, which creates smooth and gradual shading.
Glossy materials produce a mixture of both specular and diffuse reflections. In the real world, glossy or diffuse materials often appear to become shinier at oblique angles. This easy to emulate in software, by attenuating the spread of diffuse reflections according to the incoming angle.
Refraction is also fairly easy to implement, simply by allowing ray intersections to work through the insides of obstacles. The amount that light rays are bent according to the indicies of refraction is easily implemented using Snell's law. Slight specular highlights can be obtained simply by randomly choosing some light rays to reflect while allowing the rest to refract.
Pictured above is a glass orb in front of a group of coloured glossy, glassy, and metallic spheres. The same spheres without the glass orb in front are pictured on the left for comparison. Note the inversion of features at the center of the image.
Caustics
What are caustics?
Caustics are when light from a single source is concentrated in a small spot from reflections and refractions, rather than spreading out normally. Real-world examples include the patterns of light behind glasses of water, the spots of light from a disco ball, and the ripples of light under a wavy water surface.
In a path tracer, caustics are hard because they depend heavily on tiny light sources that are very difficult to hit with random sampling. They also depend on indirect and often convoluted sequences of light bounces, which makes reasoning about probabilistic sampling even more difficult. For these reason, they're often used as a sort of benchmark for how well a path tracer performs.
As has previously been stated, my path tracer is a naive implementation. The above image of a sphere of glass focusing light onto a plane was rendered at 65,536 samples per pixel which took forever. For this reason, I am not attempting to do any other work producing caustics here.
Signed Distance Fields
My path tracer allows simple geometric solids and signed distance fields to coexist in the same scene. Signed distance fields are fun because while they can describe simple shapes, they can also be used to render fractals, such as the mandelbulb, on the fly. Ray intersect tests are performed using ray marching, and surface normals are computed using finite differences. The same materials used on basic shapes above can also be used here, at no extra cost.
![](/static/img/pathtracing/mandelbulbwhole_small.png)
![](/static/img/pathtracing/mandelbulbtoplit_small.png)
![](/static/img/pathtracing/mandelbulbtopglass_small.png)
Fun/Weird Stuff
Here's a fractal made simply by placing shiny spheres right beside each other, next to some glowing and green and blue spheres.
(large image - 4.6 MB)
And here's negative light in a Cornell box.
On the top is a normal light source. When light rays hit the light source, their brightness increases. On the bottom is a negative light source (or "light sink") which decreases the amount of light returned by a bouncing light ray.
It makes no sense at all but the math is the same and it's fun to look at. Note the brighter shadows and brighter corners (negative ambient occlusion) near the bottom of the image.
Sorry it's small and grainy. This was also slow to render.
More
More images are located in the gallery
Even More
Please write to me via timstr@cs.ubc.ca and I will add more just for you