1use na::{self, RealField, Vector3};
23use crate::math::{Isometry, Point};
4use crate::query::{Ray, RayCast, RayIntersection};
5use crate::shape::{FeatureId, Triangle};
67impl<N: RealField + Copy> RayCast<N> for Triangle<N> {
8#[inline]
9fn toi_and_normal_with_ray(
10&self,
11 m: &Isometry<N>,
12 ray: &Ray<N>,
13 max_toi: N,
14_: bool,
15 ) -> Option<RayIntersection<N>> {
16let ls_ray = ray.inverse_transform_by(m);
17let mut inter = ray_intersection_with_triangle(&self.a, &self.b, &self.c, &ls_ray)?.0;
1819if inter.toi <= max_toi {
20 inter.normal = m * inter.normal;
21Some(inter)
22 } else {
23None
24}
25 }
26}
2728/// Computes the intersection between a triangle and a ray.
29///
30/// If an intersection is found, the time of impact, the normal and the barycentric coordinates of
31/// the intersection point are returned.
32pub fn ray_intersection_with_triangle<N: RealField + Copy>(
33 a: &Point<N>,
34 b: &Point<N>,
35 c: &Point<N>,
36 ray: &Ray<N>,
37) -> Option<(RayIntersection<N>, Vector3<N>)> {
38let ab = *b - *a;
39let ac = *c - *a;
4041// normal
42let n = ab.cross(&ac);
43let d = n.dot(&ray.dir);
4445// the normal and the ray direction are parallel
46if d.is_zero() {
47return None;
48 }
4950let ap = ray.origin - *a;
51let t = ap.dot(&n);
5253// the ray does not intersect the plane defined by the triangle
54if (t < na::zero() && d < na::zero()) || (t > na::zero() && d > na::zero()) {
55return None;
56 }
5758let fid = if d < N::zero() { 0 } else { 1 };
5960let d = d.abs();
6162//
63 // intersection: compute barycentric coordinates
64 //
65let e = -ray.dir.cross(&ap);
6667let mut v;
68let mut w;
69let toi;
70let normal;
7172if t < na::zero() {
73 v = -ac.dot(&e);
7475if v < na::zero() || v > d {
76return None;
77 }
7879 w = ab.dot(&e);
8081if w < na::zero() || v + w > d {
82return None;
83 }
8485let invd = na::one::<N>() / d;
86 toi = -t * invd;
87 normal = -n.normalize();
88 v = v * invd;
89 w = w * invd;
90 } else {
91 v = ac.dot(&e);
9293if v < na::zero() || v > d {
94return None;
95 }
9697 w = -ab.dot(&e);
9899if w < na::zero() || v + w > d {
100return None;
101 }
102103let invd = na::one::<N>() / d;
104 toi = t * invd;
105 normal = n.normalize();
106 v = v * invd;
107 w = w * invd;
108 }
109110Some((
111 RayIntersection::new(toi, normal, FeatureId::Face(fid)),
112 Vector3::new(-v - w + na::one(), v, w),
113 ))
114}