#ray-tracing #tui #graphics

bin+lib rtwlib

Raytracing library built in rust

6 releases

new 0.1.5 Jan 31, 2025
0.1.4 Jan 24, 2025
0.1.0 Dec 31, 2024

#69 in Rendering

Download history 155/week @ 2024-12-31 106/week @ 2025-01-07 32/week @ 2025-01-14 422/week @ 2025-01-21 131/week @ 2025-01-28

697 downloads per month
Used in rtw-tui

MIT license

59KB
1K SLoC

rtwlib

Crates.io Crates.io License Crates.io Size docs.rs

This is a simple and raytracing library, designed for simple use and modification, based on the books"raytracting in one weekend" and "Ray Tracing: the next week" by Peter Shirley. This isn't optimized for performance, so I would heavily reccomend only using it in situations where computation time isn't a concern.

This is a library, so it can be used in other projects. If you want to just mess around with the raytracer, you can use the main.rs file, which has some basic examples. If you dont want to mess with the source code, my project, rtw.tui lets you create and render scenes with a simple terminal interface.

This is mainly to learn about raytracing and rust Structs, Impl and Traits, my goal is to try and implement as much of the required functionality by hand. Right now, this is mainly just the Vec3 class and associated functions, But I plan to add a homemade random number generator, and a PNG encoder.

Features:

Usage:

To use this library, add the following to your Cargo.toml file:

[dependencies]
rtwlib = "0.1.2"

To render a scene, you need a Camera and a scene in the form of a HittableList. The following code creates a scene and camera, and renders the scene to a Vec<u8> containing the RGB values of the pixels.

use rtwlib::{camera::Camera, hittable::HittableList};

fn main() {
    let mut world = HittableList {
        objects: Vec::new(),
    };
    let mut cam = Camera::new();

    let image_bytes = cam.render_to_bytes(world, |progress| println!("Progress: {}%", progress));
    // Do something with the bytes
}

This is the bare minimum needed to render a scene and will result in a sky background, as no objects have been added to the scene.

Adding objects to the scene

Any object that implements the Hittable trait can be added to the scene. The base crate provides a Sphere object, but you can create your own objects by implementing the Hittable trait. Objects also need an associated material to inform how light bounces should be calculated, which can be any object that implements the Material trait.

fn main() {
    let mut world = HittableList::new();

    let material = Rc::new(Lambertian::new(Color::new(0.3, 0.86, 0.1))); // Create a new material with a vaguely green color
    let sphere = Sphere::new(Point3::new(0., 0., -1.), 0.5, material); // Create a new sphere at (0, 0, -1) with a radius of 0.5, using the material we just created

    world.add(sphere); // Add the sphere to the world

    // ...
}

Full example

use rtwlib::camera::*;
use rtwlib::color::Color;
use rtwlib::hittable::*;
use rtwlib::material::*;
use rtwlib::sphere::*;
use rtwlib::vec3::*;
use std::rc::Rc;

fn main() {
    let mut world = HittableList::new();

    let mat_center = Rc::new(Lambertian::new(Color::new(0.1, 0.2, 0.5)));
    let mat_right = Rc::new(Metal::new(Color::new(0.8, 0.6, 0.2), 0.0));

    world.add(Sphere::new(Point3::new(0.0, 0.0, -1.0), 0.5, mat_center));
    world.add(Sphere::new(Point3::new(1.0, 0.0, -1.0), 0.5, mat_right));

    let mut cam = Camera::new();
    cam.image_width = 400;
    cam.image_height = 225;
    cam.samples = 100;
    cam.bounces = 50;

    let image_bytes = cam.render_to_bytes(world, |progress| println!("Progress: {}%", progress));
    // Do something with the bytes, e.g., save to a file
}

for further examples, see the examplesdirectory.

Tips and tricks

If you want to save to a file, you easily render to a ppm like so:

 let buffer = cam.render_to_bytes(world, |progress| update_progress(progress, lines));

println!("\n\rDone!");
println!("Writing to {}...", args[1].to_string());
let mut file = File::create("output.ppm")?;

file.write(format!("P6\n{} {}\n255\n", cam.image_width, cam.get_height()).as_bytes())?;
file.write_all(&buffer)?;
Ok(())

You can kind of fake emmissive materials by setting the color values of a material to be greater than 1.0, or mulyiplying the base color by some large-ish number.

let mat_center = Rc::new(Lambertian::new(Color::new(0.1, 0.2, 0.8)*2));

dof2 diffuse image final33 rainbow

Future plans:

My general goal is to similtanouisly develop this, and the tui, to "test" the library. Some feature I want to add are:

  • More materials
  • More shapes
  • Multithreading
  • More object types
  • BVH optimization
  • PNG handling export support. You can also probably assume most of the second book will be implemented at some point.

Dependencies

~320KB