top of page
Search

Monte Carlo Path Tracer

  • huyuxin
  • May 30, 2020
  • 2 min read

Updated: Oct 18, 2020

In my school class advanced computer graphics, I implemented a basic rendering engine written in C++. The principle behind is Monte Carlo Path Tracer.


Comparing to ray tracing, path tracing handles material with multiple reflection/refraction property, such as a glass ball. Path tracing resolves soft shadow under an area light, beam focus of refraction material that ray tracing could not achieve.


Image rendered with ray tracing


Monte Carlo Path Tracer uses summation of samples to estimate the integration in Light Transport Equation:



It is expensive to compute integration directly. Instead we use summation as an estimation.

Here the division of Probability Density Function (pdf) reflects concept of importance sampling. When taking samples, we want to select those samples that are more likely to contribute to final result, so that the rendering result converges faster. For example, Lambert Law indicates that the bigger the angle between normal and light direction, the smaller the cosine term, thus less light contribution the light gives. Therefore, we use cosine-weighted sampling to choose more samples near top of hemisphere. To compensate the bias in choosing samples, we need to divide by PDF of the sample, as if we uniformly sample around the hemisphere.


To make rendering result converges to actual result with as few samples as possible, we used multiple importance sampling strategy. It combines BRDF estimation and Direct Light estimation with power heuristic coefficients.


Sampling with BRDF only converges slow since not all samples will hit light source eventually.

Image rendered with 100 samples using BRDF estimation only


Sampling with Direct Light converges faster, but loses the global illumination. Below rendered image looks smoother than above image, but the side face of both cubes do not reflect color of walls (red and green) anymore.

Image rendered with 100 samples using Direct Light Estimation Only


Combining both BRDF and Direct Light Estimation gives us a smooth image with global illumination.

Image rendered with 100 samples using Multiple Importance Sampling


In general we want to use Multiple Importance Sampling, MIS in short to cover both situations. When surface is more specular and light source is relatively big, BRDF estimation works better; when surface is more rough and light source is relatively small, Direct Light estimation works better.


400 Samples/Pixel, MIS, Yellow Glass Ball, Blue Reflection Mirror, Air Bubble


400 Samples/Pixel, MIS, Purple Glass Ball, Glass Cube, Texture Wall


To make rendering of complex mesh more efficient, we construct BVH tree with all mesh in the scene, and use BVH tree to accelerate path tracing.


100 Samples/Pixel, MIS, BVH Acceleration


400 Samples/Pixel, MIS, BVH Acceleration


400 Samples/Pixel, MIS, BVH Acceleration


We also implemented microfacet model, by making surface normal of a specular surface as a probability function.


400 Samples/Pixel, MIS, Microfacet Mirror


The rendering engine supports depth of field. Instead of shooting ray from a fixed camera position, we shoot ray from a range of circular plate. Only objects at depth of field will always be clear no matter where the camera ray starts


Depth of field at z=0



     Depth of field at z=-2


The rendering engine also supports homogeneous participating media. There is a probability that camera ray will attenuate and reflect in participating media, resulting in a foggy effect.


400 Samples/Pixel, Homogeneous Participating Media, Glass Ball


400 Samples/Pixel, Homogeneous Participating Media, Spot Light


 625 Samples/Pixel, Homogeneous Participating Media


The C++ program is written based on framework provided in Physically Based Rendering Theory, 3rd Edition.

 
 
 

Comments


© 2023 by Andi Banks. Proudly created with Wix.com

  • githubIcon
  • LinkedIn
bottom of page