aisth/shapes/
shapes.rs

1use std::io::BufRead;
2
3use crate::rt::ray::{Intersection, Ray};
4use crate::*;
5
6pub trait Shape {
7    fn intersect(&self, ray: &Ray, bound: &Bound<1>) -> Option<Intersection>;
8}
9
10pub struct Sphere {
11    o: Vector<3>,
12    r: Float,
13}
14
15impl Sphere {
16    pub fn new(o: Vector<3>, r: Float) -> Sphere {
17        Sphere { o, r }
18    }
19}
20
21impl Shape for Sphere {
22    fn intersect(&self, ray: &Ray, bound: &Bound<1>) -> Option<Intersection> {
23        let oo = ray.o - self.o;
24        let b = 2.0 * ray.d.dot(&oo);
25        let c = oo.dot(&oo) - self.r * self.r;
26        let delta = b * b - 4.0 * c;
27
28        if delta < 0.0 {
29            return None;
30        }
31
32        let mut distance = (-b - Float::sqrt(delta)) * 0.5;
33
34        if distance < 0.0 {
35            distance = (-b + Float::sqrt(delta)) * 0.5;
36        }
37
38        if !bound.contains(&Vector::<1>::new([distance])) {
39            return None;
40        }
41
42        let point = ray.at(distance);
43        let normal = (point - self.o).normalize();
44        Some(Intersection {
45            distance,
46            point,
47            normal,
48        })
49    }
50}
51
52pub struct Plane {
53    pub point: Vector3,
54    pub normal: Vector3,
55}
56
57impl Plane {
58    pub fn new(point: Vector3, normal: Vector3) -> Plane {
59        let normal = normal.normalize();
60        Plane { point, normal }
61    }
62}
63
64impl Shape for Plane {
65    fn intersect(&self, ray: &Ray, bound: &Interval) -> Option<Intersection> {
66        let distance = (self.point - ray.o).dot(&self.normal) / ray.d.dot(&self.normal);
67        if !bound.contains(&Vector1::new([distance])) {
68            return None;
69        }
70
71        let point = ray.at(distance);
72        let normal = self.normal;
73        Some(Intersection {
74            distance,
75            point,
76            normal,
77        })
78    }
79}
80
81#[derive(Copy, Clone, Debug)]
82pub struct Triangle {
83    pub vertices: [Vector3; 3],
84    pub normals: [Vector3; 3],
85}
86
87impl Triangle {
88    pub fn new(vertices: [Vector3; 3], normals: [Vector3; 3]) -> Triangle {
89        Triangle { vertices, normals }
90    }
91
92    pub fn build(vertices: [Vector3; 3]) -> Triangle {
93        let side_1 = vertices[1] - vertices[0];
94        let side_2 = vertices[2] - vertices[0];
95        let normal = side_1.cross(&side_2).normalize();
96        let normals = [normal, normal, normal];
97        Triangle { vertices, normals }
98    }
99}
100
101impl Shape for Triangle {
102    fn intersect(&self, ray: &Ray, bound: &Interval) -> Option<Intersection> {
103        let e_1 = self.vertices[1] - self.vertices[0];
104        let e_2 = self.vertices[2] - self.vertices[0];
105        let s = ray.o - self.vertices[0];
106        let s_1 = ray.d.cross(&e_2);
107        let s_2 = s.cross(&e_1);
108
109        let det_recip = e_1.dot(&s_1).recip();
110
111        let u = s_1.dot(&s) * det_recip;
112        if u < 0.0 || u > 1.0 {
113            return None;
114        }
115
116        let v = s_2.dot(&ray.d) * det_recip;
117        if v < 0.0 || u + v > 1.0 {
118            return None;
119        }
120
121        let distance = s_2.dot(&e_2) * det_recip;
122        if !bound.contains(&Vector1::new([distance])) {
123            return None;
124        }
125
126        let point = ray.at(distance);
127        let normal =
128            ((1.0 - u - v) * self.normals[0] + u * self.normals[1] + v * self.normals[2])
129                .normalize();
130
131        Some(Intersection {
132            distance,
133            point,
134            normal,
135        })
136    }
137}
138
139pub struct Mesh {
140    pub triangles: Vec<Triangle>,
141}
142
143impl Mesh {
144    pub fn new(triangles: Vec<Triangle>) -> Mesh {
145        Mesh { triangles }
146    }
147
148    pub fn from_obj(path: &str) -> Mesh {
149        let mut vs: Vec<Vector3> = Vec::new();
150        let mut ns: Vec<Vector3> = Vec::new();
151        let mut triangles = Vec::<Triangle>::new();
152
153        let file = std::fs::File::open(path).expect("Cannot open file.");
154        let reader = std::io::BufReader::new(file);
155
156        for ln in reader.lines().map(|l| l.unwrap()) {
157            if let Some(s) = ln.split_once(' ') {
158                match s.0 {
159                    "v" => {
160                        let v: Vec<&str> = s.1.split(' ').collect();
161                        let vertice = Vector3::new([
162                            v[0].parse::<Float>().unwrap(),
163                            v[1].parse::<Float>().unwrap(),
164                            v[2].parse::<Float>().unwrap(),
165                        ]);
166                        vs.push(vertice);
167                    }
168                    "vn" => {
169                        let n = s.1.split(' ').collect::<Vec<&str>>();
170                        let normal = Vector3::new([
171                            n[0].parse::<Float>().unwrap(),
172                            n[1].parse::<Float>().unwrap(),
173                            n[2].parse::<Float>().unwrap(),
174                        ]);
175                        ns.push(normal);
176                    }
177                    "f" => {
178                        let p = s.1.replacen("//", " ", 3);
179                        let i: Vec<&str> = p.split(' ').collect();
180                        let v = (
181                            i[0].parse::<usize>().unwrap(),
182                            i[2].parse::<usize>().unwrap(),
183                            i[4].parse::<usize>().unwrap(),
184                        );
185                        let vn = (
186                            i[1].parse::<usize>().unwrap(),
187                            i[3].parse::<usize>().unwrap(),
188                            i[5].parse::<usize>().unwrap(),
189                        );
190                        let vertices = [
191                            vs[v.0.checked_sub(1).unwrap_or(0)],
192                            vs[v.1.checked_sub(1).unwrap_or(0)],
193                            vs[v.2.checked_sub(1).unwrap_or(0)],
194                        ];
195                        let normals = [
196                            ns[vn.0.checked_sub(1).unwrap_or(0)],
197                            ns[vn.1.checked_sub(1).unwrap_or(0)],
198                            ns[vn.2.checked_sub(1).unwrap_or(0)],
199                        ];
200                        triangles.push(Triangle::new(vertices, normals));
201                    }
202                    _ => (),
203                }
204            }
205        }
206
207        Mesh { triangles }
208    }
209}
210
211impl Shape for Mesh {
212    fn intersect(&self, ray: &Ray, bound: &Interval) -> Option<Intersection> {
213        let mut intersection = None;
214        let mut b = bound.clone();
215        for t in self.triangles.iter() {
216            if let Some(candidate) = t.intersect(ray, &b) {
217                b[0].1 = candidate.distance;
218                intersection = Some(candidate);
219            }
220        }
221
222        intersection
223    }
224}
225
226