Physically Based Path Tracer
The below 3D model for the Head of Michelangelo's David bust was taken from this link. Other .obj files taken from The Stanford 3D Scanning repository |
---|
![]() |
This repository contains the implementation of a physically based monte carlo path tracer in C++. The project avoids the use of graphics API's and attempts to implement simple physically based rendering effects from scratch.
This is a project I essentially come to in my free time and is something I intend to update sporadically. If you have read the code, or tried to create a scene and have found any flaws or errors in the way things have been done — do feel free to leave an issue!
Feature Tracker / To Do
- Motion Blur
- Antialiasing
- Depth of Field
- Bounding Volume Heirarchies
- Multithread pixel processing
- Add
.obj
object support - Importance Sampling
- HDR Environment maps
-
Find a way to serialize BVH tree object (for re-use for large meshes) - Optimize and Multithread mesh BVH tree building
-
Optimize ray-triangle intersection routine - Implement additional BSDF's (Disney BSDF) and materials (sort of?)
-
Incorporate CUDA, get full rendering to happen on GPU
On halt for now, spending too much time on this
Denoiser
Noisy Render (Output) | Normal map | Albedo map | Denoised Image |
---|---|---|---|
![]() |
![]() |
![]() |
![]() |
Since the application runs on the CPU, samples per pixel needs to be limited to obtain reasonable render times (even with multi-threading).
The images shown above are denoised using Intel® Open Image Denoise. The pre-compiled binaries (given in the website) fit right into this repository to call the shell script bin/denoise
, which manages the whole denoising process and conversions.
The pre-compiled zip file (unzipped, includes a bin
and a lib
folder) needs to be moved into src/dependancies/
, for the shell script denoise
to work.
Usage
A sample binary has been uploaded with the repo (compiled on x86, as a 64 bit application), but its unlikely that it would generally work even on a system with the same configuration (try anyway, it just might). To compile in a device specific manner, you can create a Makefile using cmake (CMakeLists.txt
given) or use the given Makefile
.
After creating the Makefile using cmake and making/compiling the project (cmake .
followed by make
), the compiled binary (path-tracer
) can be found in bin/
and is to be used with a single command line argument - the name of the scene in src/scenes/
. (The folder src/scenes/
contains implementation of all the scenes in this readme file and few others. The .scene.h
files are just C++, and the files were created mostly just for organisational purposes)
> ./bin/path-tracer GlowRoom
Running this should show a progress bar, after which 3 images will be stored in output
- the noisy render (Primary output), an albedo image, and a normal map (To aid the denoising process). After these three images have been generated the denoise
binary can be run in the same way that the main one was
> ./bin/denoise GlowRoom
The resolution of the output render and the samples per pixel have been hard-coded in main.cpp
Dependancies
A simple OpenMP
call was used to multithread the loop which shoots multiple samples per pixel. The OpenMP
dependancy is included by the CmakeLists.txt
, but can easily be removed and worked without.
The project uses libraries for reading and writing images (stb_image and FreeImage) and for convenience. GLM was used for mathematical data types (vectors, matrices, etc.) and operations, but can easily be replaced by a few structs. ImageMagick is also required for commands in the denoise
shell script.
More about depandancy set up in the sub-folder src/dependancies
Resources
This project takes a lot from Ravi Ramamoorthi's course - An intro to graphics; and the repository and code largely takes its structure and features from Peter Shirley's book series.
The Disney BSDF, though poorly incorporated and incomplete, takes a lot from this repository and the corresponding blog articles. Inspiration was also taken, but to a lesser extent from tinsel from mmacklin and GLSLPathTracer from knightcrawler25.
And just like everyone ever who has written a path tracer, constant references were made to Physically Based Rendering by Matt Pharr, Wenzel Jakob, and Greg Humphreys and its repository.
Note
This was more or less a pet project to be able to learn the fundamental basics of path tracing, and with every feature I added, I got carried away. I have licensed this project under the Zlib license, and do what you may with the code but I would highly recommend not to re-use the bsdf
namespace and the core::Disney
class, since some of the lobe calculations are off.