CS283 Assignment 2: Monte Carlo Rendering

Here is my Monte Carlo Path Tracer. This path tracer is based on my ray tracer that was written for my CS184 class last semester (Links to the previous writeups are here, and here).

Frankly, the rendering quality of this path tracer is worse than what I expected. Careful readers should notice that there might be a few random black spots in some of the images. I still could not figure out what was the reason before this assignment is due. Floating point arithmetic might be the reason, but I could not find any negative value or NaN for intensity, radiance, pdf and BRDF in my path tracer.

My path tracer is designed to support HDR only, and all the images on this page are converted from EXR to PNG using Mac OSX's Preview application. The colors and dynamics may not be truthful to the original image. I am planning on implementing tone mapping in the future.

Figure 1: 2 Glass Spheres in a Cornell Box
Rendered with standard path tracing, 1024 samples per pixel, filtered.
Notice that reflection and refraction are ongoing at the same time on the spheres.

Rendering Modes

I have implemented standard path tracing and bidirectional path tracing, in addition to the ambient occlusion mode that I implemented last semester. I have also spent some time in Photon Mapping. However, I do not have time to finish it. Here is a (incorrect) direct visualization of the direct illimination map.

Standard Path Tracing

All of the implementation details are discussed in the sections below.

Figure 2, 3: Direct Lighting and Indirect Lighting for the canonical Cornell Box
Rendered with standard path tracing, 256 samples per pixel, not filtered.

Bidirectional Path Tracing

I basically followed Chapter 10 in Veach's PhD Thesis for implementing bidirectional path tracing[3]. While Veach does all his probability density function calculation with respect to surface area, I found that it is easier to calculate the pdf with respect to solid angle. I also reused all the light and eye vertices by combining them in all possible ways as suggested by Veach to increase efficiency.

Figure 4, 5: Standard and Bidirectional Path Tracing
Both rendered with 256 samples per pixel, filtered. Notice that the spheres rendered using bidirectional path tracing are brighter and clearer, as bidirectional path tracing explores light path better. However, bidirectional path tracing also increases the variance in areas near the light source, as light paths are explored around there, but undersampled.

New BRDF Models

Ashikhmin-Shirley Anisotropic Phong Model

I followed Ashikhmin and Shirley's paper[4] closely for this model. In addition to the BRDF model, they also proposed a sampling scheme based on half-vector, similar to what I used for sampling Blinn reflection; I adopted it. However, I did not implement the diffuse component of the BRDF, because I am only using it to model brushed metals at this point.

There is probably some bug in the sampling scheme for this model, since except for the reflections of the light source, the reflections on the spheres are actually isotropic. It is becasue the light source is sampled directly, and the BRDF for this model is implemented correctly. Therefore, the reflections of the light source behave as expected. Yet, indirect reflections solely depend on the sampling scheme of this BRDF model.

Figure 6: Brushed Silver and Copper Sphere
Rendered with bidirectional path tracing, 1024 samples per pixel, filtered. Silver with nu = 100 and nv = 1000, and copper with nu = 10000 and nv = 100. nu and nv are phong like components to control the shape of the specular lobe [4].


Importance Sampling

My path tracer features seven BRDF models -- Lambertian Diffuse, Oren-Nayar Microfacet, Blinn Specular, Torrance-Sparrow Microfacet, Ashikihmin-Shirley Anisotropic Phong Model, perfect specular reflection and perfect specular refraction. The first two BRDFs are simply sampled using cosine weighted hemisphere. For Blinn specular, the half vector is sampled according to the specific power of cosine. Then, the outgoing ray is obtained by reflecting the incident ray at the half vector. Torrance-Sparrow Microfacet model uses the same sampling scheme as the Blinn specular.

Of course, both perfect specular reflection and refraction's BRDFs are delta functions; importance samping does not apply.

Figure 7: Iron and Gold Spheres, n = 100
Rendered with bidirectioal path tracing, 1024 samples per pixel, filtered.
The metal spheres are modeled using Torrance-Sparrow Microfacet model with Schlick approximation of the Fresnel term. As stated above, half vector is sampled according to the specific power of consine, and the reflected ray is reflected at the half vector. And the walls are modeled using Lambertian diffuse reflection, which is sampled using a cosine weighted hemisphere.

Figure 8: Iron and Gold Spheres, n = 1000 and 10000
Rendered with bidirectioal path tracing, 1024 samples per pixel, not filtered.
As n grows, the half vector gets closer and closer to the surface normal in my sampling scheme. It follows that the reflections get closer and closer to perfect specular reflection. This shows that my importance sampling scheme for the Blinn BRDF model and the Torrance-Sparrow Microfacet model is correct.

Luminaire Sampling by Surface Area

A CDF table of lights are created by summing up the surface area of the light sources, and the light sources are chosen according to the inversion of this table. I would also like to implement luminaire sampling by intensity in the future. Of course, the pdf is converted automatically from with respect to surface area to with respect to solid angle, as all the pdfs in my path tracer is calculated with respect to solid angle.

Multiple Importance Sampling

In each of bounce / iteration in my standard path tracer, two rays are sampled as suggested by Veach[2]. The first one is sampled using the luminaire sampler, and the second one is sampled using BRDF. And they are weighted and added together using the power heuristic.

Russian Roulette

Both the path tracer and the bidirectional path tracer's rays are terminated using Russian Roulette after 1 or 2 bounces, and the weight of the ray is updated accordingly.

However, it is observed that Russian Roulette introduces lots of variance, even in scenes with only diffuse surface like the canonical Cornell Box. Scenes rendered with a fixed number of bounces have much less bright spots than the ones with rays terminated by Russian Roulette.

Figure 9, 10: With and Without Russian Roulette
Rendered with standard path tracing, 256 samples per pixel, not filtered.

Density-based Outlier Rejection Filtering

Because Russian Roulette introduces a lot of noise in my renderer, I have to implement some filter to remove the noise. I chose to implement Density-based Outlier Rejection Filtering by DeCoro[1] because it is intuitive to understand, and gives quality result.

This method identifies outliers in Monte Carlo samples using color distance. For all the samples for each pixel, the average color distance with other k samples are calculated, while k is an arbitrary tuning parameter. In the original method, samples with average color distance greater than a certain threshold are being rejected. I implemented this filtering scheme with two modifications.

First, my code automatically maintains constant brightness throughout the image. In the original implementation, DeCoro did not account for the fact that brightness is decreased because samples are being rejected. For example, when 128 samples are gathered and half of them are rejected, the sum of all the valid samples are still divided by 128, thus giving darker images. In my modification, the sum is only divided by the number of valid samples to maintain constant brightness.

Second, the color distance threshold in the original implementation is fixed. It can give a problem when the variance of different areas in an image varies a lot. When the threshold is high, outliers in the lower variance region are rejected. When the threshold is low, most of the samples in the high variance region are discarded. To fix this, I reject 10% of the samples with highest average color distance among each pixel.

Figure 11, 12: Canonical Cornell Box Before and after filtering
Rendered with bidirectional path traing, 1024 samples per pixel. Notice the filtered image on the right is virtually noise free.


  1. Christopher DeCoro, Tim Weyrich, and Szymon Rusinkiewicz. Density-based Outlier Rejection in Monte Carlo Rendering. Computer Graphics Forum (Proc. Pacific Graphics) 29(7), September 2010.
  2. Eric Veach and Leonidas J. Guibas. 1995. Optimally combining sampling techniques for Monte Carlo rendering. In Proceedings of the 22nd annual conference on Computer graphics and interactive techniques (SIGGRAPH '95), Susan G. Mair and Robert Cook (Eds.). ACM, New York, NY, USA, 419-428. DOI=10.1145/218380.218498 http://doi.acm.org/10.1145/218380.218498
  3. Eric Veach. 1998. Robust Monte Carlo Methods for Light Transport Simulation. Ph.D. Dissertation. Stanford University, Stanford, CA, USA. Advisor(s) Leonidas J. Guibas. AAI9837162.
  4. Michael Ashikhmin and Peter Shirley. 2000. An anisotropic phong BRDF model. J. Graph. Tools 5, 2 (February 2000), 25-32. DOI=10.1080/10867651.2000.10487522 http://dx.doi.org/10.1080/10867651.2000.10487522