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 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
use crate::vec3::*; pub type Colour = Vec3d; pub type Point = Vec3d; pub type Direction = Vec3d; #[derive(Clone)] pub struct Ray { pub origin: Point, pub direction: Direction, } pub struct ConstrainedRay { pub ray: Ray, pub range: (f64, f64), } pub enum HitBoxResult { Miss, Inside(f64), Outside(f64, f64), } #[derive(Clone, Debug)] pub struct BoundingBox3d { pub u: Vec3d, pub v: Vec3d, } impl BoundingBox3d { fn intersects_in_dimentions(&self, other: &Self, dimension: usize) -> bool { self.v.t[dimension] >= other.u.t[dimension] && self.u.t[dimension] <= other.v.t[dimension] } fn intersects_with_point_projected_in_dimension( &self, point: &Point, dimension: usize, ) -> bool { match dimension { 0 => { self.u.t[1] <= point.t[1] && point.t[1] <= self.v.t[1] && self.u.t[2] <= point.t[2] && point.t[2] <= self.v.t[2] } 1 => { self.u.t[0] <= point.t[0] && point.t[0] <= self.v.t[0] && self.u.t[2] <= point.t[2] && point.t[2] <= self.v.t[2] } 2 => { self.u.t[0] <= point.t[0] && point.t[0] <= self.v.t[0] && self.u.t[1] <= point.t[1] && point.t[1] <= self.v.t[1] } _ => unreachable!(), } } pub fn intersects(&self, other: &Self) -> bool { self.intersects_in_dimentions(other, 0) && self.intersects_in_dimentions(other, 1) && self.intersects_in_dimentions(other, 2) } pub fn is_hit_by_ray(&self, cray: &ConstrainedRay) -> HitBoxResult { let ray = &cray.ray; let range = &cray.range; let mut result = vec![]; for i in 0..=2 { if ray.direction.t[i] != 0.0 { { let a_x1 = (self.u.t[i] - ray.origin.t[i]) / ray.direction.t[i]; let p = ray.origin + ray.direction * a_x1; if self.intersects_with_point_projected_in_dimension(&p, i) && a_x1 >= range.0 && a_x1 <= range.1 { result.push(a_x1); } } { let a_x2 = (self.v.t[i] - ray.origin.t[i]) / ray.direction.t[i]; let p = ray.origin + ray.direction * a_x2; if self.intersects_with_point_projected_in_dimension(&p, i) && a_x2 >= range.0 && a_x2 <= range.1 { result.push(a_x2); } } } } match result.len() { 0 => HitBoxResult::Miss, 1 => HitBoxResult::Inside(*result.get(0).unwrap()), 2 => { let x = *result.get(0).unwrap(); let y = *result.get(1).unwrap(); if x < y { HitBoxResult::Outside(x, y) } else { HitBoxResult::Outside(y, x) } } _ => unreachable!(), } } } impl Ray { pub fn new(origin: Point, direction: Direction) -> Self { Self { origin, direction } } pub fn at(&self, t: f64) -> Point { &(&self.direction * t) + &self.origin } }