|
@@ -5,9 +5,26 @@
|
|
|
|
|
|
use crate::geometry::Vec3;
|
|
|
use crate::geometry::Axis;
|
|
|
+use crate::geometry::Ray;
|
|
|
use crate::mesh::Face;
|
|
|
use crate::mesh::Mesh;
|
|
|
|
|
|
+pub struct Intersection<'a> {
|
|
|
+ pub t: f32,
|
|
|
+ pub fr: FaceReference<'a>
|
|
|
+}
|
|
|
+
|
|
|
+impl PartialOrd for Intersection<'_> {
|
|
|
+ fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
|
+ return self.t.partial_cmp(&other.t);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl PartialEq for Intersection<'_> {
|
|
|
+ fn eq(&self, other: &Self) -> bool {
|
|
|
+ self.t == other.t
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
/**
|
|
|
* Axis-Aligned Bounding Box.
|
|
@@ -50,6 +67,33 @@ impl AABB {
|
|
|
|
|
|
return aabb;
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Test for intersection of ABB with Ray r.
|
|
|
+ * t is the maximum distance of the ray from its origin
|
|
|
+ */
|
|
|
+ pub fn intersect(&self, r: &Ray, t: f32) -> bool {
|
|
|
+ // See [Tavian Barnes' site](https://tavianator.com/2011/ray_box.html) for details.
|
|
|
+ let tx1 = (self.min.x - r.origin.x) * r.n_inv.x;
|
|
|
+ let tx2 = (self.max.x - r.origin.x) * r.n_inv.x;
|
|
|
+
|
|
|
+ let mut tmin = f32::min(tx1, tx2);
|
|
|
+ let mut tmax = f32::max(tx1, tx2);
|
|
|
+
|
|
|
+ let ty1 = (self.min.y - r.origin.y) * r.n_inv.y;
|
|
|
+ let ty2 = (self.max.y - r.origin.y) * r.n_inv.y;
|
|
|
+
|
|
|
+ tmin = f32::max(tmin, f32::min(ty1, ty2));
|
|
|
+ tmax = f32::min(tmax, f32::max(ty1, ty2));
|
|
|
+
|
|
|
+ let tz1 = (self.min.z - r.origin.z) * r.n_inv.z;
|
|
|
+ let tz2 = (self.max.z - r.origin.z) * r.n_inv.z;
|
|
|
+
|
|
|
+ tmin = f32::max(tmin, f32::min(tz1, tz2));
|
|
|
+ tmax = f32::min(tmax, f32::max(tz1, tz2));
|
|
|
+
|
|
|
+ return tmax >= f32::max(0.0, tmin) && tmin < t;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
|
|
@@ -63,7 +107,7 @@ pub enum BVH<'a> {
|
|
|
}
|
|
|
|
|
|
|
|
|
-#[derive(Clone)]
|
|
|
+#[derive(Copy, Clone)]
|
|
|
pub struct FaceReference<'a> {
|
|
|
m: &'a Mesh,
|
|
|
f: &'a Face
|
|
@@ -119,6 +163,81 @@ impl BVH<'_> {
|
|
|
|
|
|
return bvh;
|
|
|
}
|
|
|
+
|
|
|
+ fn intersect_ray_triangle<'a>(ray: &Ray, fr: &'a FaceReference) -> Option<Intersection<'a>> {
|
|
|
+ // See Akenine-Möller et al. Real-Time Rendering (2018), 22.8 Ray/Triangle Intersection
|
|
|
+ let p = fr.m.face_coords(fr.f);
|
|
|
+ let e1 = p[1] - p[0];
|
|
|
+ let e2 = p[2] - p[0];
|
|
|
+ let q = ray.direction.cross(e2);
|
|
|
+
|
|
|
+ let a = e1 * q;
|
|
|
+ if f32::abs(a) < 1e-9 {
|
|
|
+ return None;
|
|
|
+ }
|
|
|
+
|
|
|
+ let f = 1.0 / a;
|
|
|
+ let s = &ray.origin - p[0];
|
|
|
+
|
|
|
+ let u = f * (s * q);
|
|
|
+ if u < 0.0 {
|
|
|
+ return None
|
|
|
+ };
|
|
|
+
|
|
|
+ let r = s.cross(e1);
|
|
|
+ let v = f * (ray.direction * r);
|
|
|
+ if v < 0.0 || u + v > 1.0 {
|
|
|
+ return None;
|
|
|
+ }
|
|
|
+
|
|
|
+ let t = f * (e2 * r);
|
|
|
+
|
|
|
+ return Some(Intersection {
|
|
|
+ t: t,
|
|
|
+ fr: *fr
|
|
|
+ });
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn intersect<'a>(&'a self, r : &Ray) -> Option<Intersection<'a>> {
|
|
|
+ match self {
|
|
|
+ BVH::Leaf(aabb, frs) => {
|
|
|
+ // Early-out if the ray does not intersect the AABB
|
|
|
+ if aabb.intersect(r, f32::INFINITY) {
|
|
|
+ return None;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Make intersection tests with individual triangles
|
|
|
+ let closest_intersection : Option<Intersection> = frs.iter()
|
|
|
+ .map(|fr| Self::intersect_ray_triangle(r, fr))
|
|
|
+ .filter(|i| i.is_some())
|
|
|
+ .map(|i| i.unwrap())
|
|
|
+ .filter(|i| i.t >= 0.0)
|
|
|
+ .reduce(|a, b| if a < b { a } else { b});
|
|
|
+
|
|
|
+ return closest_intersection;
|
|
|
+ },
|
|
|
+ BVH::Node(aabb, left, right) => {
|
|
|
+ // Early-out if the ray does not intersect the AABB
|
|
|
+ if aabb.intersect(r, f32::INFINITY) {
|
|
|
+ return None;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Recurse down the tree
|
|
|
+ let left_intersection = left.intersect(r);
|
|
|
+ let right_intersection = right.intersect(r);
|
|
|
+
|
|
|
+ if left_intersection.is_some() && right_intersection.is_some() {
|
|
|
+ let (li, ri) = (left_intersection.unwrap(), right_intersection.unwrap());
|
|
|
+ return if li < ri { Some(li) } else {Some(ri)};
|
|
|
+ } else {
|
|
|
+ // At least one intersection is None.
|
|
|
+ return left_intersection.or(right_intersection);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
impl std::fmt::Display for AABB {
|