#raytracer #raytracing #ray-tracing #path-tracer

smallpt

A small ray/pathtracer in Rust, inspired by Kevin Beason’s educational 99-lines ray/pathtracer (http://www.kevinbeason.com/smallpt/)

18 releases

Uses old Rust 2015

0.3.5 Dec 29, 2019
0.3.4 Dec 29, 2019
0.3.3 May 31, 2019
0.3.2 Dec 31, 2018
0.1.12 Jun 24, 2018

#27 in Rendering

Download history 38/week @ 2021-03-31 19/week @ 2021-04-07 29/week @ 2021-04-14 45/week @ 2021-04-21 20/week @ 2021-04-28 2/week @ 2021-05-05 19/week @ 2021-05-12 1/week @ 2021-05-19 3/week @ 2021-05-26 20/week @ 2021-06-09 1/week @ 2021-06-16 2/week @ 2021-06-30 2/week @ 2021-07-07 19/week @ 2021-07-14

97 downloads per month

MIT license

34KB
658 lines

license Crates.io Build Status

A Rust implementation of a small ray/pathtracer.

Inspired by Kevin Beason's educational 99-line raytracer/pathtracer.

alt text

Supports:

  • Ray-to-Sphere
  • Ray-to-Plane
  • Ray-to-Rectangle
  • Ray-to-Triangle (slow, no acceleration yet. Soon)

Usage

# Cargo.toml
[dependencies]
smallpt = "0.3.5"

Example

extern crate smallpt;
extern crate minifb;

use smallpt::*;
use minifb::{Key, Window, WindowOptions};

fn main() {
    let num_samples = 128;
    let width = 512;
    let height = 512;

    let mut backbuffer = vec![Vec3::new(0.0, 0.0, 0.0); width * height];

    let mut scene = Scene::init();

    // Spheres
    // Mirror
    scene.add(Box::new(Sphere::new(
        16.5,
        Vec3::new(27.0, 16.5, 47.0),
        Material::new(Vec3::new(0.0, 0.0, 0.0), Vec3::new(1.0, 1.0, 1.0), BSDF::Mirror),
    )));

    // Glass
    scene.add(Box::new(Sphere::new(
        16.5,
        Vec3::new(73.0, 16.5, 78.0),
        Material::new(Vec3::new(0.0, 0.0, 0.0), Vec3::new(1.0, 1.0, 1.0), BSDF::Glass),
    )));

    // Planes
    // Bottom
    scene.add(Box::new(Plane::new(
        Vec3::new(0.0, 0.0, 0.0),
        Vec3::new(0.0, 1.0, 0.0),
        Material::new(Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.75, 0.75, 0.75), BSDF::Diffuse),
    )));

    // Left
    scene.add(Box::new(Plane::new(
        Vec3::new(1.0, 0.0, 0.0),
        Vec3::new(1.0, 0.0, 0.0),
        Material::new(Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.75, 0.25, 0.25), BSDF::Diffuse),
    )));

    // Right
    scene.add(Box::new(Plane::new(
        Vec3::new(99.0, 0.0, 0.0),
        Vec3::new(-1.0, 0.0, 0.0),
        Material::new(Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.25, 0.25, 0.75), BSDF::Diffuse),
    )));

    // Front
    scene.add(Box::new(Plane::new(
        Vec3::new(0.0, 0.0, 0.0),
        Vec3::new(0.0, 0.0, 1.0),
        Material::new(Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.75, 0.75, 0.75), BSDF::Diffuse),
    )));

    // Back
    scene.add(Box::new(Plane::new(
        Vec3::new(0.0, 0.0, 170.0),
        Vec3::new(0.0, 0.0, -1.0),
        Material::new(Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 0.0), BSDF::Diffuse),
    )));

    // Top
    scene.add(Box::new(Plane::new(
        Vec3::new(0.0, 81.6, 0.0),
        Vec3::new(0.0, -1.0, 0.0),
        Material::new(Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.75, 0.75, 0.75), BSDF::Diffuse),
    )));

    // Light (emissive rectangle)
    scene.add(Box::new(Rectangle::new(
        Vec3::new(50.0, 81.5, 50.0),
        Vec3::new(0.0, -1.0, 0.0),
        Vec3::new(1.0, 0.0, 0.0),
        Vec3::new(0.0, 0.0, 1.0),
        33.0,
        33.0,
        Material::new(Vec3::new(12.0, 12.0, 12.0), Vec3::new(0.0, 0.0, 0.0), BSDF::Diffuse),
    )));

    let camera = Camera {
        origin: Vec3::new(50.0, 50.0, 200.0),
        forward: Vec3::new(0.0, -0.05, -1.0).normalize(),
        right: Vec3::new(1.0, 0.0, 0.0).normalize(),
        up: Vec3::new(0.0, 1.0, 0.0).normalize(),
    };

    let mut buffer: Vec<u32> = vec![0; width * height];
    let mut window = Window::new("smallpt in Rust", width, height, WindowOptions::default())
        .unwrap_or_else(|e| {
            panic!("{}", e);
        });

    // Render
    let mut num_rays = 0;
    trace(&scene, &camera, width, height, num_samples, &mut backbuffer, &mut num_rays);

    while window.is_open() && !window.is_key_down(Key::Escape) {
        for i in 0..width * height {
            let color = saturate(tonemap(backbuffer[i]));

            let r = (color.x * 255.0).round() as u32;
            let g = (color.y * 255.0).round() as u32;
            let b = (color.z * 255.0).round() as u32;

            buffer[i] = (r << 16) | (g << 8) | b;
        }

        window.update_with_buffer(&buffer, width, height).unwrap();
    }
}

Architecture

alt text

Dependencies

~5.5MB
~99K SLoC