Factor out ray computations that are shared for all triangles.

This commit is contained in:
Nathan Vegdahl 2019-07-06 09:19:53 +09:00
parent 4b612e2d1a
commit 646139efda
3 changed files with 53 additions and 36 deletions

View File

@ -284,8 +284,9 @@ impl<'a> Surface for RectangleLight<'a> {
let p4 = Point::new(dim.0 * 0.5, dim.1 * -0.5, 0.0) * space_inv;
// Test against two triangles that make up the light
let ray_pre = triangle::RayTriPrecompute::new(dir);
for tri in &[(p1, p2, p3), (p3, p4, p1)] {
if let Some((t, b0, b1, b2)) = triangle::intersect_ray(orig, dir, max_t, *tri) {
if let Some((t, b0, b1, b2)) = triangle::intersect_ray(orig, ray_pre, max_t, *tri) {
if t < max_t {
if rays.is_occlusion(ray_idx) {
isects[ray_idx] = SurfaceIntersection::Occlude;

View File

@ -5,23 +5,14 @@ use crate::{
math::{Point, Vector},
};
/// Intersects `ray` with `tri`, returning `Some((t, b0, b1, b2))`, or `None`
/// if no intersection.
///
/// Returned values:
///
/// * `t` is the ray t at the hit point.
/// * `b0`, `b1`, and `b2` are the barycentric coordinates of the triangle at
/// the hit point.
///
/// Uses the ray-triangle test from the paper "Watertight Ray/Triangle
/// Intersection" by Woop et al.
pub fn intersect_ray(
ray_orig: Point,
ray_dir: Vector,
ray_max_t: f32,
tri: (Point, Point, Point),
) -> Option<(f32, f32, f32, f32)> {
#[derive(Debug, Copy, Clone)]
pub struct RayTriPrecompute {
i: (usize, usize, usize),
s: (f32, f32, f32),
}
impl RayTriPrecompute {
pub fn new(ray_dir: Vector) -> RayTriPrecompute {
// Calculate the permuted dimension indices for the new ray space.
let (xi, yi, zi) = {
let xabs = ray_dir.x().abs();
@ -46,17 +37,41 @@ pub fn intersect_ray(
let sy = dir_y / dir_z;
let sz = 1.0 / dir_z;
RayTriPrecompute {
i: (xi, yi, zi),
s: (sx, sy, sz),
}
}
}
/// Intersects `ray` with `tri`, returning `Some((t, b0, b1, b2))`, or `None`
/// if no intersection.
///
/// Returned values:
///
/// * `t` is the ray t at the hit point.
/// * `b0`, `b1`, and `b2` are the barycentric coordinates of the triangle at
/// the hit point.
///
/// Uses the ray-triangle test from the paper "Watertight Ray/Triangle
/// Intersection" by Woop et al.
pub fn intersect_ray(
ray_orig: Point,
ray_pre: RayTriPrecompute,
ray_max_t: f32,
tri: (Point, Point, Point),
) -> Option<(f32, f32, f32, f32)> {
// Calculate vertices in ray space.
let p0 = tri.0 - ray_orig;
let p1 = tri.1 - ray_orig;
let p2 = tri.2 - ray_orig;
let p0x = p0.get_n(xi) - (sx * 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 p1y = p1.get_n(yi) - (sy * p1.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 p0x = p0.get_n(ray_pre.i.0) - (ray_pre.s.0 * p0.get_n(ray_pre.i.2));
let p0y = p0.get_n(ray_pre.i.1) - (ray_pre.s.1 * p0.get_n(ray_pre.i.2));
let p1x = p1.get_n(ray_pre.i.0) - (ray_pre.s.0 * p1.get_n(ray_pre.i.2));
let p1y = p1.get_n(ray_pre.i.1) - (ray_pre.s.1 * p1.get_n(ray_pre.i.2));
let p2x = p2.get_n(ray_pre.i.0) - (ray_pre.s.0 * p2.get_n(ray_pre.i.2));
let p2y = p2.get_n(ray_pre.i.1) - (ray_pre.s.1 * p2.get_n(ray_pre.i.2));
// Calculate scaled barycentric coordinates.
let mut e0 = (p1x * p2y) - (p1y * p2x);
@ -82,9 +97,9 @@ pub fn intersect_ray(
}
// Calculate t of hitpoint.
let p0z = sz * p0.get_n(zi);
let p1z = sz * p1.get_n(zi);
let p2z = sz * p2.get_n(zi);
let p0z = ray_pre.s.2 * p0.get_n(ray_pre.i.2);
let p1z = ray_pre.s.2 * p1.get_n(ray_pre.i.2);
let p2z = ray_pre.s.2 * p2.get_n(ray_pre.i.2);
let t_scaled = (e0 * p0z) + (e1 * p1z) + (e2 * p2z);
// Check if the hitpoint t is within ray min/max t.

View File

@ -183,6 +183,7 @@ impl<'a> Surface for TriangleMesh<'a> {
let mut hit_tri = unsafe { std::mem::uninitialized() };
let mut hit_tri_indices = unsafe { std::mem::uninitialized() };
let mut hit_tri_data = unsafe { std::mem::uninitialized() };
let ray_pre = triangle::RayTriPrecompute::new(rays.dir(ray_idx));
for tri_idx in idx_range.clone() {
let tri_indices = self.indices[tri_idx];
@ -229,7 +230,7 @@ impl<'a> Surface for TriangleMesh<'a> {
// Test ray against triangle
if let Some((t, b0, b1, b2)) = triangle::intersect_ray(
rays.orig(ray_idx),
rays.dir(ray_idx),
ray_pre,
rays.max_t(ray_idx),
tri,
) {