4 releases (2 breaking)
0.3.0 | Feb 19, 2024 |
---|---|
0.2.0 | Jun 10, 2021 |
0.1.1 | May 27, 2021 |
0.1.0 | May 27, 2021 |
#63 in Rendering engine
1MB
5K
SLoC
Crystal Ball
Crystal Ball is a path tracing library written in Rust.
It uses rayon for parallelization and can save the rendered image in various formats thanks to the image crate.
Note that Crystal Ball is a hobby project and will most likely see a lot of API changes in future versions.
Features
- Multithreaded CPU rendering
- Save rendered images in various formats
- Environment textures
- General purpose PBR material
- Shapes: spheres and triangle meshes
- Easily create your own textures, materials, and shapes
- Load glTF files
- Depth of field
- Bounding Volume Hierarchies
- Optional denoising using Open Image Denoise
Usage
Basic Example
A basic example rendering two spheres.
use std::default::Default;
use std::sync::Arc;
use crystal_ball::prelude::*;
fn main() -> Result<(), Error> {
let objects = vec![
Object::new(
Arc::new(Sphere::new()),
Arc::new(PbrMaterial {
base_color: Color::new(1.0, 0.45, 0.31),
..Default::default()
}),
),
Object::new(
Arc::new(
Sphere::new()
.translate(Vec3::new(0.0, -101.0, 0.0))
.scale_xyz(Vec3::splat(100.0)),
),
Arc::new(PbrMaterial::default()),
),
];
let scene = Scene {
objects,
camera: Camera::default().translate(Vec3::new(0.0, 0.0, 5.0)),
..Default::default()
};
let engine = RenderEngine::default();
let image = engine.render(&scene);
image.write("basic.png")?;
Ok(())
}
This produces the following image:
There are many other examples showcasing Crystal Ball's capabilities, demonstrating how to use the different features.
Coordinate System
Crystal Ball uses a right-handed coordinate system where
- +X points right
- +Y points up
- +Z points to the screen
Denoising
Crystal ball can optionally denoise rendered images using the Rust bindings for Open Image Denoise.
To use this feature you need to install Open Image Denoise
and set the environment variable OIDN_DIR
to the root directory of the Open Image Denoise installation.
Enable the oidn
feature in your Cargo.toml
:
[dependencies.crystal_ball]
version = "0.3.0"
features = ["oidn"]
Now you can use the denoise method in your Rust code.
fn main() -> Result<(), Error> {
// ...
let mut image = engine.render(&scene);
image.denoise()?;
image.write("image_denoised.png")?;
}
Optimization
The performance of your path tracing code will benefit greatly from compiler optimizations,
at the cost of longer compile times.
To easily switch between quick compilation and highly optimized code generation,
you can put the following lines into your Cargo.toml
.
For a detailed explanation of what this does,
see the Cargo Book.
[package]
# ...
[profile.dev]
opt-level = 3
[profile.release]
# Reduce binary size
#panic = "abort"
#strip = "symbols"
# Improve performance but increase compile time
lto = "fat"
codegen-units = 1
Feature Flags
Optional Features
Name | description |
---|---|
oidn |
Image denoising using Open Image Denoise |
References/Resources
- https://raytracing.github.io/books/RayTracingInOneWeekend.html
- https://github.com/ekzhang/rpt
- https://tavianator.com/2014/ray_triangle.html
- https://www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle/moller-trumbore-ray-triangle-intersection
- https://en.wikipedia.org/wiki/Möller–Trumbore_intersection_algorithm
- https://pbrt.org/
- https://www.rs-pbrt.org/
Dependencies
~11–19MB
~246K SLoC