Monte-Carlo Ray Tracer
ray traced image

This is a java ray tracer I wrote for a course on advanced rendering (COM S 517) taught by Kavita Bala which I took during the first term of my masters degree. There was some basic code provided for us which loaded up the scene and saved the image. We implemented a bunch of stuff on top.

Here is a list of what we did.

BRDFs
  • Lambertian reflector
  • Lambertian emitter
  • Ward (anisotropic)
  • Cook-Torrance
Acceleration structure
  • KD-tree
Box-filter antialiasing
  • Uniform multisampling
  • Stratified multisampling
  • N-Rooks multisampling
Direct illumination sampling
  • Uniform sampling
  • (Emitter) Power sampling
  • Weighted balance sampling
Indirect illumination sampling
  • Uniform sampling
  • Stratified sampling
  • Cosine weighted sampling
  • Stratified cosine weighted sampling
  • BRDF weighted sampling
Depth recursion stopping criterion
  • Russian roulette

BRDF

These were implemented directly from the original papers. Ward's paper contains a formula for generating BRDF weighted samples already, so we didn't have to sweat over that one. We did not implement BRDF sampling for the Cook-Torrance BRDF.

Acceleration Structure

We used a KD-tree to improve the performance of the ray tracer. This is basically a binar tree where each cell is partitioned along the x-, y-, or z-axis depending on which split will provide better performance. The splitting heuristic I used compares weighs the number of primitives of each child by the surface area of the child cell and divides it by the surface area of the parent cell. This prevents boxes from becoming too small.

Anti-Aliasing

We implemented basic antialiasing by running a box filter over every pixel (simple averaging). However, we implemented various pixel sampling strategies. The N-Rooks sampling strategy breaks the pixel into a grid of N2 boxes and takes N samples such that each sample is the only sample in its row and column.

Direct Illumination

To speed up the ray tracer, we compute direct and indirect illumination separately, both using Monte Carlo sampling. We sampled the lights uniformly or based on the total power emitted by them. We could also compute the direct lighting as part of the indirect lighting computation, but that slows down the rendering quite a bit--in fact, computing these separately is really a type of importance sampling. We also have a hybrid, "weighted-balance" scheme which will alternately sample the lights or do importance sampling on the BRDF. This one is useful to sample the specular direction of highly specular BRDFs.

Indirect Illumination

We did quite a bit of work here, mixing stratified sampling with the cosine-based importance sampling strategies and a BRDF sampling strategy.

Depth Recursion Stopping Criterion

Here we used Russian roulette, which is an unbiased stopping criterion that simply kills the ray or recurses with a (user) predefined probability.

Image-Based Rendering

To conclude the course, we did some image-based rendering. A GUI was provided to move the camera around, and we simply reprojected the ray tracing samples to the new camera location, interpolating the fill in the gaps.

Results

Here are some of the images we produced along with sampling methods used to generate each one. Note the color bleeding when indirect illumination is enabled.

scene11_0
Rays/pixel: 1
Antialiasing: none
Direct illum.: on
Direct illum. rays/point: 1
Sampling: center of emitter
Indirect illum. rays/point: 0
Sampling: none
Render time: 4.7s
scene11_1
Rays/pixel: 1
Antialiasing: none
Direct illum.: on
Direct illum. rays/point: 1
Sampling: center of emitter
Indirect illum. rays/point: 0
Sampling: none
Render time: 3.4s
scene12
Rays/pixel: 1
Antialiasing: none
Direct illum.: on
Direct illum. rays/point: 1
Sampling: uniform
Indirect illum. rays/point: 0
Sampling: none
Render time: 1.5s
scene13
Rays/pixel: 9
Antialiasing: uniform
Direct illum.: on
Direct illum. rays/point: 1
Sampling: uniform
Indirect illum. rays/point: 0
Sampling: none
Render time: 8.2s
scene14
Rays/pixel: 9
Antialiasing: stratified
Direct illum.: on
Direct illum. rays/point: 1
Sampling: uniform
Indirect illum. rays/point: 0
Sampling: none
Render time: 8.3s
scene15
Rays/pixel: 1
Antialiasing: none
Direct illum.: on
Direct illum. rays/point: 1
Sampling: uniform
Indirect illum. rays/point: 0
Sampling: none
Render time: 1.5s
scene16
Rays/pixel: 1
Antialiasing: none
Direct illum.: on
Direct illum. rays/point: 1
Sampling: uniform
Indirect illum. rays/point: 0
Sampling: none
Render time: 1.4s
scene17
Rays/pixel: 1
Antialiasing: none
Direct illum.: on
Direct illum. rays/point: 49
Sampling: uniform
Indirect illum. rays/point: 0
Sampling: none
Render time: 21.1s
scene18
Rays/pixel: 49
Antialiasing: uniform
Direct illum.: on
Direct illum. rays/point: 1
Sampling: uniform
Indirect illum. rays/point: 0
Sampling: none
Render time: 42.2s
scene19
Rays/pixel: 1
Antialiasing: none
Direct illum.: on
Direct illum. rays/point: 16
Sampling: uniform
Indirect illum. rays/point: 0
Sampling: none
Render time: 10.9s
scene20
Rays/pixel: 1
Antialiasing: none
Direct illum.: on
Direct illum. rays/point: 16
Sampling: uniform
Indirect illum. rays/point: 0
Sampling: none
Render time: 11.0s
scene21
Rays/pixel: 1
Antialiasing: none
Direct illum.: on
Direct illum. rays/point: 16
Sampling: power
Indirect illum. rays/point: 0
Sampling: none
Render time: 10.3s
scene22
Rays/pixel: 49
Antialiasing: uniform
Direct illum.: on
Direct illum. rays/point: 1
Sampling: uniform
Indirect illum. rays/point: 1
Sampling: uniform
Render time: 85.2s
scene23
Rays/pixel: 49
Antialiasing: uniform
Direct illum.: on
Direct illum. rays/point: 1
Sampling: uniform
Indirect illum. rays/point: 1
Sampling: cosine
Render time: 83.4s
scene24
Rays/pixel: 9
Antialiasing: uniform
Direct illum.: on
Direct illum. rays/point: 1
Sampling: uniform
Indirect illum. rays/point: 0
Sampling: none
Render time: 8.5s
scene25
Rays/pixel: 49
Antialiasing: uniform
Direct illum.: on
Direct illum. rays/point: 1
Sampling: uniform
Indirect illum. rays/point: 1
Sampling: uniform
Render time: 84.1s
scene26
Rays/pixel: 49
Antialiasing: uniform
Direct illum.: on
Direct illum. rays/point: 1
Sampling: uniform
Indirect illum. rays/point: 1
Sampling: brdf
Render time: 85.0s
scene27
Rays/pixel: 49
Antialiasing: uniform
Direct illum.: on
Direct illum. rays/point: 1
Sampling: uniform
Indirect illum. rays/point: 1
Sampling: brdf
Render time: 87.9s
scene28
Rays/pixel: 200
Antialiasing: uniform
Direct illum.: on
Direct illum. rays/point: 1
Sampling: uniform
Indirect illum. rays/point: 1
Sampling: brdf
Render time: 369.3s
scene29
Rays/pixel: 49
Antialiasing: uniform
Direct illum.: off
Direct illum. rays/point: 0
Sampling: none
Indirect illum. rays/point: 1
Sampling: uniform
Render time: 45.8s
scene30
Rays/pixel: 49
Antialiasing: uniform
Direct illum.: off
Direct illum. rays/point: 0
Sampling: none
Indirect illum. rays/point: 1
Sampling: uniform
Render time: 47.4s
scene31
Rays/pixel: 49
Antialiasing: uniform
Direct illum.: on
Direct illum. rays/point: 1
Sampling: uniform
Indirect illum. rays/point: 1
Sampling: uniform
Render time: 52.7s
scene32
Rays/pixel: 49
Antialiasing: uniform
Direct illum.: off
Direct illum. rays/point: 0
Sampling: none
Indirect illum. rays/point: 1
Sampling: brdf
Render time: 36.4s
scene33
Rays/pixel: 49
Antialiasing: uniform
Direct illum.: on
Direct illum. rays/point: 1
Sampling: weighted balance
Indirect illum. rays/point: 1
Sampling: brdf
Render time: 85.8s
scene34
Rays/pixel: 1
Antialiasing: none
Direct illum.: on
Direct illum. rays/point: 100
Sampling: uniform
Indirect illum. rays/point: 0
Sampling: none
Render time: 75.9s