lumiere/
aabb.rs

1use std::mem;
2
3use crate::{interval::Interval, ray::Ray, Point3};
4
5#[derive(Debug, Clone)]
6pub struct AABB {
7    x: Interval,
8    y: Interval,
9    z: Interval,
10}
11
12impl AABB {
13    pub fn new(x: Interval, y: Interval, z: Interval) -> Self {
14        Self { x, y, z }
15    }
16
17    pub fn from_points(a: Point3, b: Point3) -> Self {
18        Self {
19            x: Interval::new(a.x.min(b.x), a.x.max(b.x)),
20            y: Interval::new(a.y.min(b.y), a.y.max(b.y)),
21            z: Interval::new(a.z.min(b.z), a.z.max(b.z)),
22        }
23    }
24
25    pub fn from_boxes(a: &Self, b: &Self) -> Self {
26        Self {
27            x: Interval::from_intervals(&a.x, &b.x),
28            y: Interval::from_intervals(&a.y, &b.y),
29            z: Interval::from_intervals(&a.z, &b.z),
30        }
31    }
32
33    pub fn axis(&self, n: usize) -> &Interval {
34        match n {
35            0 => &self.x,
36            1 => &self.y,
37            2 => &self.z,
38            _ => {
39                panic!("invalid interval index passed into aabb {}", n);
40            }
41        }
42    }
43
44    pub fn hit(&self, r: &Ray, ray_t: &Interval) -> bool {
45        for i in 0..3 {
46            let inv_d = 1. / r.direction[i];
47            let mut t0 = (self.axis(i).min - r.origin[i]) * inv_d;
48            let mut t1 = (self.axis(i).max - r.origin[i]) * inv_d;
49            if inv_d < 0. {
50                mem::swap(&mut t0, &mut t1);
51            }
52
53            let ray_tmin = t0.max(ray_t.min);
54            let ray_tmax = t1.min(ray_t.max);
55
56            if ray_tmax <= ray_tmin {
57                return false;
58            }
59        }
60        true
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use crate::{interval, ray::Ray, vec3::Vec3, Point3};
67
68    use super::AABB;
69
70    #[test]
71    fn hit_bb_linear() {
72        let p1 = Point3::new(3., 0., 0.);
73        let p2 = Point3::new(4., 1., 0.);
74
75        let bb = AABB::from_points(p1, p2);
76
77        let ray_origin = Point3::new(0., 0.5, 0.);
78        let ray_direction = Vec3::new(1., 0., 0.);
79        let r = Ray::new(ray_origin, ray_direction, 0.);
80
81        assert!(bb.hit(&r, &interval::UNIVERSE));
82    }
83
84    #[test]
85    fn miss_bb_linear() {
86        let p1 = Point3::new(3., 0., 0.);
87        let p2 = Point3::new(4., 1., 1.);
88
89        let bb = AABB::from_points(p1, p2);
90
91        dbg!(&bb);
92
93        let ray_origin = Point3::new(0., -0.5, 0.);
94        let ray_direction = Vec3::new(1., 0., 0.);
95        let r = Ray::new(ray_origin, ray_direction, 0.);
96
97        assert!(!bb.hit(&r, &interval::UNIVERSE));
98    }
99
100    #[test]
101    fn bb_join() {
102        let p0_0 = Point3::new(-1., -1., -1.);
103        let p0_1 = Point3::new(1., 1., 1.);
104        let p1_0 = Point3::new(-0.3, -0.3, 0.7);
105        let p1_1 = Point3::new(0.3, 0.3, 1.3);
106
107        let bb_0 = AABB::from_points(p0_0, p0_1);
108        let bb_1 = AABB::from_points(p1_0, p1_1);
109
110        let _bb = AABB::from_boxes(&bb_0, &bb_1);
111        todo!();
112    }
113}