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