crystal_ball 0.2.0

A path tracing library written in Rust.
Documentation

crystal_ball

Latest Version API Documentation

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.

Features

  • Multithreaded CPU rendering
  • Save rendered images in various formats
  • Environment textures
  • Materials: diffuse, metallic, emissive, refractive
  • Shapes: currently only spheres are supported
  • Depth of field
  • Optional denoising using OpenImageDenoise

Usage

Getting Started

Create a new project:

cargo init [project-name]
cd [project-name]

Add crystal_ball = 0.2.0 to the [dependencies] section of the Cargo.toml file.

Replace the content of src/main.rs with the following minimal example:

use std::path::Path;
use crystal_ball::prelude::*;

fn main() {
    let objects: Vec<Box<dyn Shape>> = vec![
        Box::new(
            Sphere::new()
                .with_material(Box::new(Diffuse::new(Color::new(1.0, 0.45, 0.31))))
        ),
        Box::new(
            Sphere::new()
                .with_center(Vec3::new(0.0, -101.0, 0.0))
                .with_radius(100.0)
        ),
    ];

    let scene = Scene::new().with_objects(objects);

    let engine = RenderEngine::new(64, 4); // Samples and max bounces
    let image = engine.render(&scene);

    image
        .write(Path::new("example_render.png"))
        .expect("Error writing rendered image");
}

Compile and run the project using cargo run --release.

Denoising

Crystal ball can optionally denoise rendered images using the Rust bindings for OpenImageDenoise.

To use this feature you need to install OpenImageDenoise and set the environment variable OIDN_DIR to the root directory of the OpenImageDenoise installation.

Enable the oidn feature in your Cargo.toml:

[dependencies.crystal_ball]
version = "0.2.0"
features = ["oidn"]

Now you can use the denoise method in your Rust code.

fn main() {
    // ...
    let mut image = engine.render(&scene);
    image
        .denoise()
        .write(Path::new("output/example_render.png"))
        .expect("Error writing rendered image");
}

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.

# Required by `strip = "symbols"` (requires nightly toolchain)
#cargo-features = ["strip"]

[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

With this in place you can quickly compile using cargo run. To get full optimization use cargo run --release.

To massively reduce the size of the executable, you can use strip = symbols, provided you have the strip cargo feature (cargo-features = ["strip"]). However, this requires the nightly toolchain.

References/Resources