obvhs/
triangle.rs

1//! Triangle representation in 3D space.
2
3use bytemuck::{Pod, Zeroable};
4use glam::{Mat4, Vec2, Vec3A, vec2};
5
6use crate::{Boundable, Transformable, aabb::Aabb, ray::Ray};
7
8#[derive(Clone, Copy, Default, Debug, Zeroable)]
9pub struct Triangle {
10    pub v0: Vec3A,
11    pub v1: Vec3A,
12    pub v2: Vec3A,
13}
14
15unsafe impl Pod for Triangle {}
16
17impl Triangle {
18    /// Compute the normal of the triangle geometry.
19    #[inline(always)]
20    pub fn compute_normal(&self) -> Vec3A {
21        let e1 = self.v1 - self.v0;
22        let e2 = self.v2 - self.v0;
23        e1.cross(e2).normalize_or_zero()
24    }
25
26    /// Compute the bounding box of the triangle.
27    #[inline(always)]
28    pub fn aabb(&self) -> Aabb {
29        Aabb::from_points(&[self.v0, self.v1, self.v2])
30    }
31
32    /// Find the distance (t) of the intersection of the `Ray` and this Triangle.
33    /// Returns f32::INFINITY for miss.
34    #[inline(always)]
35    pub fn intersect(&self, ray: &Ray) -> f32 {
36        // TODO not very water tight from the back side in some contexts (tris with edges at 0,0,0 show 1px gap)
37        // Find out if this is typical of Möller
38        // Based on Fast Minimum Storage Ray Triangle Intersection by T. Möller and B. Trumbore
39        // https://madmann91.github.io/2021/04/29/an-introduction-to-bvhs.html
40        let cull_backface = false;
41        let e1 = self.v0 - self.v1;
42        let e2 = self.v2 - self.v0;
43        let n = e1.cross(e2);
44
45        let c = self.v0 - ray.origin;
46        let r = ray.direction.cross(c);
47        let inv_det = 1.0 / n.dot(ray.direction);
48
49        let u = r.dot(e2) * inv_det;
50        let v = r.dot(e1) * inv_det;
51        let w = 1.0 - u - v;
52
53        //let hit = u >= 0.0 && v >= 0.0 && w >= 0.0;
54        //let valid = if cull_backface {
55        //    inv_det > 0.0 && hit
56        //} else {
57        //    inv_det != 0.0 && hit
58        //};
59
60        // Note: differs in that if v == -0.0, for example will cause valid to be false
61        let hit = u.to_bits() | v.to_bits() | w.to_bits();
62        let valid = if cull_backface {
63            (inv_det.to_bits() | hit) & 0x8000_0000 == 0
64        } else {
65            inv_det != 0.0 && hit & 0x8000_0000 == 0
66        };
67
68        if valid {
69            let t = n.dot(c) * inv_det;
70            if t >= ray.tmin && t <= ray.tmax {
71                return t;
72            }
73        }
74
75        f32::INFINITY
76    }
77
78    // https://github.com/RenderKit/embree/blob/0c236df6f31a8e9c8a48803dada333e9ea0029a6/kernels/geometry/triangle_intersector_moeller.h#L9
79    #[cfg(all(
80        any(target_arch = "x86", target_arch = "x86_64"),
81        target_feature = "sse2"
82    ))]
83    pub fn intersect_embree(&self, ray: &Ray) -> f32 {
84        // Not watertight from the front side? Looks similar to what above looks like from the back side.
85
86        // This uses the orientation from https://madmann91.github.io/2021/04/29/an-introduction-to-bvhs.html
87
88        let cull_backface = false;
89        let v0 = self.v0;
90        let e1 = self.v0 - self.v1;
91        let e2 = self.v2 - self.v0;
92        let ng = e1.cross(e2);
93
94        // Calculate denominator
95        let o = ray.origin;
96        let d = ray.direction;
97        let c = v0 - o;
98        let r = c.cross(d);
99        let den = (-ng).dot(d);
100        let abs_den = den.abs();
101
102        fn signmsk(x: f32) -> f32 {
103            #[cfg(target_arch = "x86")]
104            use std::arch::x86::*;
105            #[cfg(target_arch = "x86_64")]
106            use std::arch::x86_64::*;
107            unsafe {
108                let mask = _mm_set1_ps(-0.0);
109                let x_vec = _mm_set_ss(x);
110                let sign_bit = _mm_and_ps(x_vec, mask);
111                _mm_cvtss_f32(sign_bit)
112                //_mm_cvtss_f32(_mm_and_ps(
113                //    _mm_set_ss(x),
114                //    _mm_castsi128_ps(_mm_set1_epi32(-2147483648i32)),
115                //))
116            }
117        }
118
119        let sgn_den = signmsk(den).to_bits();
120
121        // Perform edge tests
122        let u = f32::from_bits(r.dot(e2).to_bits() ^ sgn_den);
123        let v = f32::from_bits(r.dot(e1).to_bits() ^ sgn_den);
124        // TODO simd uv?
125
126        // Perform backface culling
127        // OG
128        //let valid = if cull_backface {
129        //    den < 0.0 && u >= 0.0 && v >= 0.0 && u + v <= abs_den
130        //} else {
131        //    den != 0.0 && u >= 0.0 && v >= 0.0 && u + v <= abs_den
132        //};
133
134        let w = abs_den - u - v;
135        let valid = if cull_backface {
136            ((-den).to_bits() | u.to_bits() | v.to_bits() | (abs_den - u - v).to_bits())
137                & 0x8000_0000
138                == 0
139        } else {
140            den != 0.0 && ((u.to_bits() | v.to_bits() | w.to_bits()) & 0x8000_0000) == 0
141        };
142
143        if !valid {
144            return f32::INFINITY;
145        }
146
147        // Perform depth test
148        let t = f32::from_bits((-ng).dot(c).to_bits() ^ sgn_den);
149
150        if abs_den * ray.tmin < t && t <= abs_den * ray.tmax {
151            return t;
152        }
153
154        f32::INFINITY
155    }
156
157    #[inline(always)]
158    pub fn compute_barycentric(&self, ray: &Ray) -> Vec2 {
159        let e1 = self.v0 - self.v1;
160        let e2 = self.v2 - self.v0;
161        let ng = e1.cross(e2).normalize_or_zero();
162        let r = ray.direction.cross(self.v0 - ray.origin);
163        vec2(r.dot(e2), r.dot(e1)) / ng.dot(ray.direction)
164    }
165}
166
167impl Boundable for Triangle {
168    #[inline(always)]
169    fn aabb(&self) -> Aabb {
170        self.aabb()
171    }
172}
173
174impl Transformable for &mut Triangle {
175    fn transform(&mut self, matrix: &Mat4) {
176        self.v0 = matrix.transform_point3a(self.v0);
177        self.v1 = matrix.transform_point3a(self.v1);
178        self.v2 = matrix.transform_point3a(self.v2);
179    }
180}
181
182impl<T> Transformable for T
183where
184    T: AsMut<[Triangle]>,
185{
186    fn transform(&mut self, matrix: &Mat4) {
187        self.as_mut().iter_mut().for_each(|mut triangle| {
188            triangle.transform(matrix);
189        });
190    }
191}