summaryrefslogtreecommitdiff
path: root/racer-tracer/src/material/dialectric.rs
blob: 5f3aa02ac842dd98ae3c4eb3aec51b7b4a774c53 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
use crate::{
    material::Material,
    ray::Ray,
    util::random_double,
    vec3::{dot, reflect, refract, Color},
};

pub struct Dialectric {
    refraction_index: f64,
}

impl Dialectric {
    pub fn new(refraction_index: f64) -> Self {
        Self { refraction_index }
    }

    fn reflectance(cosine: f64, refraction_index: f64) -> f64 {
        // Schlick approximation
        let mut r0 = (1.0 - refraction_index) / (1.0 + refraction_index);
        r0 = r0 * r0;
        r0 + (1.0 - r0) * (1.0 - cosine).powf(5.0)
    }
}

impl Material for Dialectric {
    fn scatter(
        &self,
        ray: &crate::ray::Ray,
        rec: &crate::geometry::HitRecord,
    ) -> Option<(Ray, Color)> {
        let refraction_ratio = if rec.front_face {
            1.0 / self.refraction_index
        } else {
            self.refraction_index
        };

        let unit_direction = &ray.direction().unit_vector();
        let cos_theta = f64::min(dot(&-unit_direction, &rec.normal), 1.0);
        let sin_theta = f64::sqrt(1.0 - cos_theta * cos_theta);

        let cannot_refract = refraction_ratio * sin_theta > 1.0;

        let direction = if cannot_refract
            || Dialectric::reflectance(cos_theta, refraction_ratio) > random_double()
        {
            reflect(unit_direction, &rec.normal)
        } else {
            refract(unit_direction, &rec.normal, refraction_ratio)
        };

        Some((Ray::new(rec.point, direction), Color::new(1.0, 1.0, 1.0)))
    }
}