mesh_geometry/queries/
ray_triangle.rs1use crate::{Float, Point3, Vec3};
4
5#[derive(Debug, Clone, Copy)]
7pub struct Ray<T: Float> {
8 pub origin: Point3<T>,
10 pub dir: Vec3<T>,
12}
13
14pub fn ray_intersects_triangle<T: Float>(
18 ray: Ray<T>,
19 a: Point3<T>,
20 b: Point3<T>,
21 c: Point3<T>,
22) -> Option<(T, T, T)> {
23 let epsilon = T::from(1e-8).unwrap();
24 let edge1 = b - a;
25 let edge2 = c - a;
26 let pvec = ray.dir.cross(edge2);
27 let det = edge1.dot(pvec);
28 if det.abs() < epsilon {
29 return None; }
31 let inv_det = det.recip();
32 let tvec = ray.origin - a;
33 let u = tvec.dot(pvec) * inv_det;
34 if u < T::zero() || u > T::one() {
35 return None;
36 }
37 let qvec = tvec.cross(edge1);
38 let v = ray.dir.dot(qvec) * inv_det;
39 if v < T::zero() || u + v > T::one() {
40 return None;
41 }
42 let t = edge2.dot(qvec) * inv_det;
43 if t > epsilon {
44 Some((t, u, v))
45 } else {
46 None
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53 use crate::{Point3, Vec3};
54
55 #[test]
56 fn hit_center() {
57 let ray = Ray {
58 origin: Point3::new(0.1_f64, 0.1, -1.0),
59 dir: Vec3::new(0.0, 0.0, 1.0),
60 };
61 let a = Point3::new(0.0, 0.0, 0.0);
62 let b = Point3::new(1.0, 0.0, 0.0);
63 let c = Point3::new(0.0, 1.0, 0.0);
64 let hit = ray_intersects_triangle(ray, a, b, c).unwrap();
65 assert!((hit.0 - 1.0).abs() < 1e-8);
66 assert!(hit.1 + hit.2 < 1.0);
68 }
69
70 #[test]
71 fn miss_ray() {
72 let ray = Ray {
73 origin: Point3::new(2.0, 2.0, -1.0),
74 dir: Vec3::new(0.0, 0.0, 1.0),
75 };
76 assert!(ray_intersects_triangle(
77 ray,
78 Point3::new(0., 0., 0.),
79 Point3::new(1., 0., 0.),
80 Point3::new(0., 1., 0.)
81 )
82 .is_none());
83 }
84}