As a 2 week project in Brown’s graduate graphics class, I implemented Path Tracing in C++ and Eigen. This method is physically accurate unlike a regular ray tracer, and involves tracing light paths from the camera and surfaces to perform Monte-Carlo integration for a surface’s luminescence.

The program supports diffuse, glossy, mirrored, and refractive materials. Since path tracing is expensive, I optimized rendering time by I using OpenMP to parallelize parts of the computation as well as a Bounding Volume Hierarchy to speed up ray intersection.

Renders with 100 samples per pixel taking 5-10 seconds.

For lower variance in our light sampling, I splitted integrating for direct and indirect lighting. For direct, the sensible thing is to shoot rays directly at a random point on a randomly sampled light source, whereas for indirect lighting, we recursively trace paths. The result is a much smoother render with the same sample per pixel count.

Renders with 100 samples per pixel with and without direct lighting optimization.

For sampling light bounces, I sampled porpotional to the BRDF (Bidirectional reflectance distribution function) instead of uniformly over the hemisphere tangent to the surface. This is essential to get good renders of specular materials.

Renders with only 10 samples per pixel with and without importance sampling.

Lastly, I threw in depth of field and attenuated the refracted light for more realistic looking renders.