bs-trace 0.3.0

Free RayTracing software
Documentation
use crate::image::prelude::Colour;
use crate::linalg;
use crate::trace::prelude::Vec3;
use rand::RngCore;
use std::fmt::Debug;

pub trait Material: Debug + Send + Sync {
    fn colour(&self) -> Colour;
    fn bounce(
        &self,
        rng: &mut Box<dyn RngCore>,
        incident_direction: Vec3,
        surface_normal: Vec3,
    ) -> Option<Vec3>;
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Lambertian {
    pub colour: Colour,
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Metal {
    pub colour: Colour,
    pub fuzz: f64,
}

impl Lambertian {
    pub const fn new(colour: Colour) -> Self {
        Self { colour }
    }
}

impl Material for Lambertian {
    fn colour(&self) -> Colour {
        self.colour
    }

    fn bounce(
        &self,
        rng: &mut Box<dyn RngCore>,
        incident_direction: Vec3,
        surface_normal: Vec3,
    ) -> Option<Vec3> {
        loop {
            let bounce_direction = linalg::rand::random_unit3(rng) + surface_normal;
            if bounce_direction.mag() < 1.0e-9 {
                continue;
            }
            break Some(bounce_direction.normalised());
        }
    }
}

impl Metal {
    pub const fn new(colour: Colour, fuzz: f64) -> Self {
        Self { colour, fuzz }
    }
}

impl Material for Metal {
    fn colour(&self) -> Colour {
        self.colour
    }

    fn bounce(
        &self,
        rng: &mut Box<dyn RngCore>,
        incident_direction: Vec3,
        surface_normal: Vec3,
    ) -> Option<Vec3> {
        let b_height = incident_direction.dot(surface_normal);
        let pure_bounce = incident_direction - surface_normal * 2.0 * b_height;
        let fuzz_displacement = linalg::rand::random_unit3(rng) * self.fuzz;
        let bounce = pure_bounce + fuzz_displacement;
        if bounce.dot(surface_normal) < 0.0 {
            None
        } else {
            Some(bounce)
        }
    }
}