-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtriangle.rs
90 lines (81 loc) · 2.41 KB
/
triangle.rs
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
use glam::{Affine3A, Vec3A};
use crate::{
hit::Hit,
material::{Material},
object::Object,
ray::Ray,
Vertex,
};
#[derive(Debug)]
pub struct Triangle {
pub normal: Vec3A,
pub corners: [Vertex; 3],
material: Box<dyn Material + Send + Sync>,
}
impl Triangle {
pub fn new<M>(corners @ [v0, v1, v2]: [Vertex; 3], material: M) -> Self
where
M: Material + Send + Sync + 'static,
{
let e1 = v1 - v0;
let e2 = v2 - v0;
let normal = e1.cross(e2).normalize();
Triangle {
normal,
corners,
material: Box::new(material),
}
}
}
impl Object for Triangle {
fn intersection(&self, ray: &Ray) -> Vec<Hit> {
let epsilon = 0.0001;
let [c0, c1, c2] = self.corners.clone();
// implementing the MT algorithm which exploits Cramer's rule
let e1 = c1 - c0;
let e2 = c2 - c0;
let h = ray.direction.cross(e2);
let a = e1.dot(h);
if a > -epsilon && a < epsilon {
return Vec::new(); // ray parallel to triangle
}
let f = 1. / a;
let s = ray.position - c0;
let u = f * s.dot(h);
if u < 0. || u > 1. {
return Vec::new(); // condition from barycentric coords
}
let q = s.cross(e1);
let v = f * ray.direction.dot(q);
if v < 0. || u + v > 1. {
return Vec::new(); // condition from barycentric coords
}
let t = f * e2.dot(q);
if t > epsilon {
// successful ray intersection
let plane_normal = e1.cross(e2);
let normal = if plane_normal.dot(ray.direction) < 0. {
plane_normal
} else {
-plane_normal
};
vec![Hit {
t,
entering: true,
object_hit: self,
material: &*self.material,
position: ray.position + ray.direction * t,
normal: normal.normalize(),
incident: ray.clone(),
}]
} else {
Vec::new()
}
}
fn apply_transform(&mut self, t: Affine3A) {
self.normal = t.transform_vector3a(self.normal);
for corner in &mut self.corners {
*corner = t.transform_point3a(*corner);
}
}
}