This is a wavelength aware physically based 3D rendering engine written in Rust. The main focus is in implementing concepts in a concise and readable manner, however there are some performance optimizations. This project uses packed_simd
in much of the code where possible.
The purpose is to help me become more familiar with Rust and with general Light Transport algorithms. However if it helps the reader learn more about these concepts, that would be great.
The following is an image rendered with the BDPT integrator. The light at the top appears dark because it's emitting mainly in the downward direction. The walls' color uses the spectral data from the cornell website. The gem's material information matches that of moissanite, from refractiveindex.info. The color noise is from the fact that this version of the bdpt integrator doesn't use HWSS, and from the fact that most of the illumination into the scene is split into very colorful caustics which overall increase color variance.
See this for some more renders and details
Most of the integrators use NEE and MIS, and they trace using single wavelength sampling.
Supported integrators:
- Path Tracing, described on wikipedia here
Experimental integrators:
- Light tracing, also known as particle tracing, where light is emitted from light sources in the scene and traced until it hits the camera.
- Bidirectional Path Tracing, described in PBRT here
In addition, much of the code emphasizes matching reality as closely as possible, including the following features:
- Output format:
- The renderer outputs an .exr file in Linear RGB space, and a .png file in sRGB space.
- custom exposure values for the sRGB tonemapper are supported. the default behavior is to set the brightest pixel on the screen to white.
- The renderer outputs an .exr file in Linear RGB space, and a .png file in sRGB space.
- Colors and Lights:
- Colors on the film are represented in CIE XYZ color space. This is then tonemapped to linear RGB space and sRGB space according to the wikipedia article
- Lights can have physically correct spectral power distribution functions, including blackbody distributions and distributions with peaks at certain frequencies
- Colors are implemented as Spectral Response Functions, under the hood they are bounded spectral power distributions
- in general, for lights and for colors, those spectral response functions are implemented as curves, and multiple curve types are supported. see curves.rs and math/spectral.rs for more information. See also rust_cg_math
- Metals and Dielectrics are wavelength-dependent:
- Dielectrics use a curve (struct Curve) to represent their varying index of refraction with respect to wavelength.
- This allows for physically correct Dispersion. The curve used is typically a curve matching the first two terms of Cauchy's equation.
- Metals use multiple curves to represent their index of refraction and extinction coefficient with respect to wavelength.
- This allows for physically correct color and reflectance behavior so that Gold, Copper, and other metals can be represented and traced accurately.
- Dielectrics use a curve (struct Curve) to represent their varying index of refraction with respect to wavelength.
However, there are some concepts that I'm still unfamiliar with or that I'm working on that aren't properly implemented yet. that includes the following:
- Image reconstruction theory and pixel filtering. this seems to be very important for Light tracing, but less important for normal Path tracing.
- Real physical units for Radiance and for Camera importance.
Requirements are Rust nightly.
Building and running should be as simple as executing cargo run
from the shell while in the project root directory.
to change render settings, modify the provided file at data/config.toml
it comes preloaded with many options and most are commented out.
- implement basic config file to reduce unnecessary recompilations. Done, at config.rs, data files at data/config.toml
- add simple random walk abstraction. Done, at integrator/bdpt/helpers.rs
- implement glossy and transmissive bsdfs. Done, implemented GGX, at materials/ggx.rs
- add common color spectral reflectance functions. Done, implemented at curves.rs
- implement correct XYZ to sRGB conversion. Done, at tonemap.rs
- implement parsing CSV files as curves and using them as ior and kappa values. Done, at parsing.rs
- implement instances. Somewhat done, still more to do. at geometry/mod.rs
- implement basic accelerator. Done, at accelerator.rs
- implement environment sampling. Mostly done, still more to do (proper pdfs when generating rays from the environment). at world.rs and environment.rs
- implement light emission sampling to generate rays from lights. Done, part of the material trait at material.rs
- implement BVH
- implement spectral power distribution importance sampling. requires computing the CDF of curves.
- implement scene parser to reduce compilations even more
- implement light tracing
- implement BDPT
- refactor bsdf trait methods to reduce duplication
- simd based HWSS. WIP on a local branch.
- basic mediums. WIP on a local branch.
- implement real units for radiance and camera importance
- research image reconstruction theory and implement proper pixel filtering
Thanks to Nova, for helping me figure out some implementation details and generally helping me learn rust.
I am referencing this blog post and code while working on the BDPT integrator, so thanks to the author.
Thanks to members of the Rendering & Lighting (offline) discord server for pointing me in the right direction in fixing some color output issues.
I used this to implement the BVH, so thanks to svenstaro. I modified it to use my AABB implementation and other math routines, but for the most part the algorithm is unchanged.
I grabbed some sRGB basis functions for upsampling textures from this paper/repo. Thanks to the authors.
Please view this as a hobby or reference implementation. If you find any issues, please feel free to log them on GitHub's issue tracker, or submit a pull request to fix them :)
If you're so inclined, buy me a coffee at my ko-fi