Cleaned up implementation of ray/triangle intersection test.

This commit is contained in:
Nathan Vegdahl 2017-07-10 00:39:09 -07:00
parent f371e0643a
commit a1840ec408

View File

@ -17,28 +17,19 @@ use ray::Ray;
/// Intersection" by Woop et al. /// Intersection" by Woop et al.
pub fn intersect_ray(ray: &Ray, tri: (Point, Point, Point)) -> Option<(f32, f32, f32, f32)> { pub fn intersect_ray(ray: &Ray, tri: (Point, Point, Point)) -> Option<(f32, f32, f32, f32)> {
// Calculate the permuted dimension indices for the new ray space. // Calculate the permuted dimension indices for the new ray space.
let zi = { let (xi, yi, zi) = {
let xabs = ray.dir.x().abs(); let xabs = ray.dir.x().abs();
let yabs = ray.dir.y().abs(); let yabs = ray.dir.y().abs();
let zabs = ray.dir.z().abs(); let zabs = ray.dir.z().abs();
if xabs > yabs && xabs > zabs { if xabs > yabs && xabs > zabs {
0 (1, 2, 0)
} else if yabs > zabs { } else if yabs > zabs {
1 (2, 0, 1)
} else { } else {
2 (0, 1, 2)
} }
}; };
let (xi, yi) = if ray.dir.get_n(zi) >= 0.0 {
let xi = if zi == 2 { 0 } else { zi + 1 };
let yi = if xi == 2 { 0 } else { xi + 1 };
(xi, yi)
} else {
let xi = if zi == 2 { 0 } else { zi + 1 };
let yi = if xi == 2 { 0 } else { xi + 1 };
(yi, xi)
};
let dir_x = ray.dir.get_n(xi); let dir_x = ray.dir.get_n(xi);
let dir_y = ray.dir.get_n(yi); let dir_y = ray.dir.get_n(yi);
@ -54,29 +45,23 @@ pub fn intersect_ray(ray: &Ray, tri: (Point, Point, Point)) -> Option<(f32, f32,
let p1 = tri.1 - ray.orig; let p1 = tri.1 - ray.orig;
let p2 = tri.2 - ray.orig; let p2 = tri.2 - ray.orig;
let p0x = p0.get_n(xi) - sx * p0.get_n(zi); let p0x = p0.get_n(xi) - (sx * p0.get_n(zi));
let p0y = p0.get_n(yi) - sy * p0.get_n(zi); let p0y = p0.get_n(yi) - (sy * p0.get_n(zi));
let p1x = p1.get_n(xi) - sx * p1.get_n(zi); let p1x = p1.get_n(xi) - (sx * p1.get_n(zi));
let p1y = p1.get_n(yi) - sy * p1.get_n(zi); let p1y = p1.get_n(yi) - (sy * p1.get_n(zi));
let p2x = p2.get_n(xi) - sx * p2.get_n(zi); let p2x = p2.get_n(xi) - (sx * p2.get_n(zi));
let p2y = p2.get_n(yi) - sy * p2.get_n(zi); let p2y = p2.get_n(yi) - (sy * p2.get_n(zi));
// Calculate scaled barycentric coordinates. // Calculate scaled barycentric coordinates.
let mut e0 = (p2x * p1y) - (p2y * p1x); let mut e0 = (p1x * p2y) - (p1y * p2x);
let mut e1 = (p0x * p2y) - (p0y * p2x); let mut e1 = (p2x * p0y) - (p2y * p0x);
let mut e2 = (p1x * p0y) - (p1y * p0x); let mut e2 = (p0x * p1y) - (p0y * p1x);
// Fallback to test against edges using double precision. // Fallback to test against edges using double precision.
if e0 == 0.0 || e1 == 0.0 || e2 == 0.0 { if e0 == 0.0 || e1 == 0.0 || e2 == 0.0 {
let p2xp1y = p2x as f64 * p1y as f64; e0 = ((p1x as f64 * p2y as f64) - (p1y as f64 * p2x as f64)) as f32;
let p2yp1x = p2y as f64 * p1x as f64; e1 = ((p2x as f64 * p0y as f64) - (p2y as f64 * p0x as f64)) as f32;
e0 = (p2xp1y - p2yp1x) as f32; e2 = ((p0x as f64 * p1y as f64) - (p0y as f64 * p1x as f64)) as f32;
let p0xp2y = p0x as f64 * p2y as f64;
let p0yp2x = p0y as f64 * p2x as f64;
e1 = (p0xp2y - p0yp2x) as f32;
let p1xp0y = p1x as f64 * p0y as f64;
let p1yp0x = p1y as f64 * p0x as f64;
e2 = (p1xp0y - p1yp0x) as f32;
} }
// Check if the ray hit the triangle. // Check if the ray hit the triangle.
@ -97,15 +82,11 @@ pub fn intersect_ray(ray: &Ray, tri: (Point, Point, Point)) -> Option<(f32, f32,
let t = (e0 * p0z) + (e1 * p1z) + (e2 * p2z); let t = (e0 * p0z) + (e1 * p1z) + (e2 * p2z);
// Check if the hitpoint t is within ray min/max t. // Check if the hitpoint t is within ray min/max t.
if det >= 0.0 { if det > 0.0 && (t <= 0.0 || t > (ray.max_t * det)) {
if t <= 0.0 || t > (ray.max_t * det) {
return None; return None;
} } else if det < 0.0 && (t >= 0.0 || t < (ray.max_t * det)) {
} else {
if -t <= 0.0 || -t > (ray.max_t * -det) {
return None; return None;
} }
}
// Return t and the hitpoint barycentric coordinates. // Return t and the hitpoint barycentric coordinates.
let inv_det = 1.0 / det; let inv_det = 1.0 / det;