raytracer 0.2.2

Toy raytracer in Rust
Documentation
use crate::{
    HitData,
    Material,
    Ray, ray,
    Vec3, dot, len, reflect, refract
};



/// Returns [`Schlick's approximation`].
///
/// [`Schlick's approximation`]: https://en.wikipedia.org/wiki/Schlick%27s_approximation
pub fn schlick(cosine: f32, refraction_index: f32) -> f32 {
    let r0 = (1f32 - refraction_index) / (1f32 + refraction_index);
    let r0 = r0 * r0;

    r0 + (1f32 - r0) * (1f32 - cosine).powi(5)
}



/// Glass (dielectric) [`Material`].
///
/// Used for shapes that are transparent.
///
/// [`Material`]: trait.Material.html
pub struct Glass {
    /// Defines how much red, green and blue light this material reflects.
    albedo: Vec3,
    /// Refractive index of this material.
    ///
    /// Refracted angle depends on this index, the higher the difference,
    /// the higher the angle change.
    ///
    /// Refraction indexes of common materials:
    ///
    /// * Air      1.0
    /// * Water    1.3
    /// * Glass    1.3 - 1.7
    /// * Diamond  2.4
    pub refraction_index: f32
}

impl Glass {
    pub fn new(albedo: Vec3, refraction_index: f32) -> Glass {
        Glass {albedo, refraction_index}
    }
}

impl Material for Glass {
    fn scatter(&self, ray_in: &Ray, hit_data: &HitData) -> (Vec3, Ray) {
        let dt = dot!(ray_in.direction, hit_data.normal);
        let ray_in_mag = len!(ray_in.direction);

        let (normal, n, cosine) = match dt > 0f32 {
            true => (
                -hit_data.normal,
                self.refraction_index,
                self.refraction_index * dt / ray_in_mag
            ),
            false => (
                hit_data.normal,
                self.refraction_index.recip(),
                -dt / ray_in_mag
            )
        };

        let attenuation = self.albedo;
        let scattered = match refract!(ray_in.direction, normal, n) {
            Some(refracted) if rand::random::<f32>() > schlick(cosine, self.refraction_index) => {
                ray!(hit_data.point, refracted)
            },
            _ => {
                let reflected = reflect!(ray_in.direction, hit_data.normal);

                ray!(hit_data.point, reflected)
            }
        };

        (attenuation, scattered)
    }
}