Live demo: https://dennis.life/demo/pathtracer (Definitely runs in Google Chrome on Win10)
This is a path tracer written in Rust, intended to be compiled into WebAssembly (WASM). The included TypeScript Web App periodically invokes the WASM path tracer, and provides a GUI to interact with it.
This project was written as a research prototype for the Utrecht University course Advanced Graphics.
The raytracer is converted to a path tracer. This path tracer contains the following special features:
- Photon-Based Next Event Estimation - Prior to path tracing the scene, photons are sent from the light sources into the scene. These photons are used to find the most-contributing light sources for any particular hit point. (See file
src/data/photon_tree.rs
andsrc/tracer.rs
) - Adaptive Sampling - Samples are mainly taken for pixels that need it the most. (E.g. wherever the most noise and fireflies are - See file
src/graphics/sampling_strategy.rs
)
Compiling the application yourself can be a bit troublesome, as compilers for three languages (TypeScript, Rust, Elm) need to be present.
If no changes are made, I recommend using the live demo website listed at the top.
If you do compile it yourself, follow the steps below.
The Elm compiler can be downloaded through NPM. NPM is distributed with Node.js .
Then install Elm globally with:
npm install -g elm
Webpack is used to compile and bundle all targets. The compile scripts are made for Webpack. Install Webpack globally as follows:
npm install -g webpack webpack-cli
The Rust compiler can be downloaded from:
The Nightly Rust build is required, as SIMD instructions are currently experimental. For this, run: rustup default nightly
.
Now all necessary system-wide tools should be available. Any other tools/libraries should be obtainable as part of the project's npm
setup process. Inside the root of this project invoke:
npm install
This installs all local dependencies (into the node_modules/
directory). To run the project in dev-mode, invoke:
npm run serve
This starts a HTTP server at https://localhost:9000/, with the project running.
Note that the application may not run in all browsers. It surely works in Google Chrome, but (especially multi-threading) may not work in other browsers. Be aware of this.
The GUI buttons on the righthand-side are rather self-explanatory. Further controls are:
- WASD + PageUp + PageDown translate the camera
- Arrow keys rotate the camera
The main architecture is divided between the TypeScript part and the Rust part. Rust implements the actual tracing of rays into (hardcoded) scenes. The TypeScript part handles the GUI (buttons + controls), and guides the multi-threading (as browsers can only multi-thread through WebWorkers). The general structure of both parts is outlines below:
The Rust sourcecode is located in the src
directory. Some important files are described below.
lib.rs
- The compilation entry point of the application (not really important)wasm_interface.rs
- All public-interface functions. All functions that are called by TypeScript are placed here.tracer.rs
- Contains code for tracing a single ray (recursively) into a scenescenes.rs
- The hardcoded scenesmain.rs
- The entry-point when not compiling to WebAssembly (but to native). Used for debugging and benchmarking.data/photon_tree.rs
- An octree for storing photons. All nodes contain a CDF for the contributing light sourcesgraphics/
scene.rs
- General scene description. Contains methods for tracing rays (and shadow rays) into the scene. Also contains code for traversing the BVH.material.rs
- The material class (reflection, diffuse, refraction; potentially with textures)bvh.rs
- Constructs a 2-way BVHbvh4.rs
- Collapses a 4-way BVH to a 2-way BVHsampling_strategy.rs
- Contains the random and adaptive sampling strategiesprimitives/
- Contains all implemented primitives (each implementsTracable
fromgraphics/ray.rs
)
The TypeScript sourcecode mainly deals with the GUI and the properly spawning of WebWorkers to attain proper multi-threading.
Regarding multi-threading: The WASM module is compiled once, and then passed onto 8 WebWorkers. Each of these WebWorkers gets a random subset (partition) of the pixels in the scene. Once all WebWorkers (running the WASM module) are done with raytracing for their pixels, the resulting buffer is written to the screen by the main thread.
Some important files are described below.
client/
- The code running on the main threadindex.ts
- The "main" file
shared/
- Library code that is shared (w.r.t. the compiler) between the main thread and the workersworker/
- Code that is running on the webworkerworker.ts
- The "main" file for the webworker. Mainly contains code to handle messages from the main thread
- wasm-bindgen hello world example - Setup for Rust to WASM with Webpack
- Scratchapixel - Nice explanation on refraction and fresnel
- demofox.org - Raytracing - Explanation on refraction and Beer's law
- Torus ray intersection
- My old raytracer - This I wrote during my BSc (RuG - Computer Graphics), from which I reused some primitive intersection code (some of which I probably took from the course slides or provided code templates).
- "Shallow Bounding Volume Hierarchies for Fast SIMD Ray Tracing of Incoherent Rays" by H. Dammertz and J. Hanika and A. Keller - On 4-way BVH SIMD structures
- "Adaptive Collapsing on Bounding Volume Hierarchies for Ray-Tracing" by A. Susano Pinto - On 2-way BVH collapsing
- "Stanford bunny" by G. Turk and M. Levoy
- "Efficient data structures and sampling of many light sources for Next Event Estimation" by Andreas Mikolajewski - On the PNEE
- "Adaptive Sampling and Reconstruction using Greedy Error Minimization" by F. Rousselle, C. Knaus, and M. Zwicker - On Adaptive Sampling
- Utrecht University course slides for Advanced Graphics.
BSD-3 - See the LICENSE
file
The included fonts (which I absolutely needed) were published under the Apache License, Version 2.0.