aboutsummaryrefslogtreecommitdiffstats
path: root/src/sphere.rs
blob: 573f891be0febd103cdfdfa4dacbe80f20094961 (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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use crate::hittable::{Hit, Hittable};
use crate::material::Material;
use crate::ray::Ray;
use cgmath::prelude::*;
use cgmath::{dot, Vector3};
use core::borrow::Borrow;

pub struct Sphere {
    center0: Vector3<f64>,
    center1: Vector3<f64>,
    time0: f64,
    time1: f64,
    radius: f64,
    material: Box<dyn Material + std::marker::Sync>,
}

impl Sphere {
    pub fn new(
        center: Vector3<f64>,
        time0: f64,
        time1: f64,
        radius: f64,
        material: Box<dyn Material + std::marker::Sync>,
    ) -> Sphere {
        Sphere {
            center0: center,
            center1: center,
            time0,
            time1,
            radius,
            material,
        }
    }

    pub fn new_moving(
        center0: Vector3<f64>,
        center1: Vector3<f64>,
        time0: f64,
        time1: f64,
        radius: f64,
        material: Box<dyn Material + std::marker::Sync>,
    ) -> Sphere {
        Sphere {
            center0,
            center1,
            time0,
            time1,
            radius,
            material,
        }
    }

    pub fn center(&self, time: f64) -> Vector3<f64> {
        self.center0
            + ((time - self.time0) / (self.time1 - self.time0)) * (self.center1 - self.center0)
    }
}

impl Hittable for Sphere {
    fn is_hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<Hit> {
        let oc = ray.orig - self.center(ray.time);
        let a = ray.dir.magnitude2();
        let b = dot(oc, ray.dir);
        let c = oc.magnitude2() - self.radius * self.radius;
        let discriminant = b * b - a * c;

        if discriminant > 0.0 {
            let soln = (-b - discriminant.sqrt()) / a;
            if soln < t_max && soln > t_min {
                return Some(Hit::new(
                    ray,
                    soln,
                    (ray.at(soln) - self.center(ray.time)) / self.radius,
                    self.material.borrow(),
                ));
            }
            let soln = (-b + discriminant.sqrt()) / a;
            if soln < t_max && soln > t_min {
                return Some(Hit::new(
                    ray,
                    soln,
                    (ray.at(soln) - self.center(ray.time)) / self.radius,
                    self.material.borrow(),
                ));
            }
        }
        None
    }
}