Leaf triangle intersection now loops over triangles per ray.
This is the inverse of what was being done before, which was to loop over all of the rays for each triangle. At the moment, this actually appears to be a tiny bit slower, but it should allow for future optimizations testing against multiple triangles at once.
This commit is contained in:
parent
4f7335db8c
commit
4b612e2d1a
|
@ -14,6 +14,8 @@ use crate::{
|
|||
|
||||
use super::{triangle, Surface, SurfaceIntersection, SurfaceIntersectionData};
|
||||
|
||||
const MAX_LEAF_TRIANGLE_COUNT: usize = 3;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct TriangleMesh<'a> {
|
||||
time_sample_count: usize,
|
||||
|
@ -93,7 +95,7 @@ impl<'a> TriangleMesh<'a> {
|
|||
};
|
||||
|
||||
// Build BVH
|
||||
let accel = BVH4::from_objects(arena, &mut indices[..], 3, |tri| {
|
||||
let accel = BVH4::from_objects(arena, &mut indices[..], MAX_LEAF_TRIANGLE_COUNT, |tri| {
|
||||
&bounds
|
||||
[(tri.3 as usize * time_sample_count)..((tri.3 as usize + 1) * time_sample_count)]
|
||||
});
|
||||
|
@ -132,38 +134,64 @@ impl<'a> Surface for TriangleMesh<'a> {
|
|||
|
||||
self.accel
|
||||
.traverse(rays, ray_stack, |idx_range, rays, ray_stack| {
|
||||
for tri_idx in idx_range {
|
||||
let tri_indices = self.indices[tri_idx];
|
||||
let tri_count = idx_range.end - idx_range.start;
|
||||
|
||||
// For static triangles with static transforms, cache them.
|
||||
let is_cached = self.time_sample_count == 1 && space.len() <= 1;
|
||||
let mut tri = if is_cached {
|
||||
let tri = (
|
||||
// Build the triangle cache if we can!
|
||||
let is_cached = ray_stack.ray_count_in_next_task() >= tri_count
|
||||
&& self.time_sample_count == 1
|
||||
&& space.len() <= 1;
|
||||
let mut tri_cache = [unsafe { std::mem::uninitialized() }; MAX_LEAF_TRIANGLE_COUNT];
|
||||
if is_cached {
|
||||
for tri_idx in idx_range.clone() {
|
||||
let i = tri_idx - idx_range.start;
|
||||
let tri_indices = self.indices[tri_idx];
|
||||
|
||||
// For static triangles with static transforms, cache them.
|
||||
tri_cache[i] = (
|
||||
self.vertices[tri_indices.0 as usize],
|
||||
self.vertices[tri_indices.1 as usize],
|
||||
self.vertices[tri_indices.2 as usize],
|
||||
);
|
||||
if space.is_empty() {
|
||||
tri
|
||||
} else {
|
||||
(
|
||||
tri.0 * static_mat_space,
|
||||
tri.1 * static_mat_space,
|
||||
tri.2 * static_mat_space,
|
||||
)
|
||||
if !space.is_empty() {
|
||||
tri_cache[i].0 = tri_cache[i].0 * static_mat_space;
|
||||
tri_cache[i].1 = tri_cache[i].1 * static_mat_space;
|
||||
tri_cache[i].2 = tri_cache[i].2 * static_mat_space;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test each ray against the triangles.
|
||||
ray_stack.do_next_task(|ray_idx| {
|
||||
let ray_idx = ray_idx as usize;
|
||||
|
||||
if rays.is_done(ray_idx) {
|
||||
return;
|
||||
}
|
||||
|
||||
let ray_time = rays.time(ray_idx);
|
||||
|
||||
// Calculate the ray space, if necessary.
|
||||
let mat_space = if space.len() > 1 {
|
||||
// Per-ray transform, for motion blur
|
||||
lerp_slice(space, ray_time).inverse()
|
||||
} else {
|
||||
unsafe { std::mem::uninitialized() }
|
||||
static_mat_space
|
||||
};
|
||||
|
||||
// Test each ray against the current triangle.
|
||||
ray_stack.do_next_task(|ray_idx| {
|
||||
let ray_idx = ray_idx as usize;
|
||||
let ray_time = rays.time(ray_idx);
|
||||
// Iterate through the triangles and test the ray against them.
|
||||
let mut non_shadow_hit = false;
|
||||
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() };
|
||||
for tri_idx in idx_range.clone() {
|
||||
let tri_indices = self.indices[tri_idx];
|
||||
|
||||
// Get triangle if necessary
|
||||
if !is_cached {
|
||||
tri = if self.time_sample_count == 1 {
|
||||
let tri = if is_cached {
|
||||
let i = tri_idx - idx_range.start;
|
||||
tri_cache[i]
|
||||
} else {
|
||||
let mut tri = if self.time_sample_count == 1 {
|
||||
// No deformation motion blur, so fast-path it.
|
||||
(
|
||||
self.vertices[tri_indices.0 as usize],
|
||||
|
@ -188,29 +216,14 @@ impl<'a> Surface for TriangleMesh<'a> {
|
|||
|
||||
(p0, p1, p2)
|
||||
};
|
||||
}
|
||||
|
||||
// Transform triangle if necessary, and get transform space.
|
||||
let mat_space = if !space.is_empty() {
|
||||
if space.len() > 1 {
|
||||
// Per-ray transform, for motion blur
|
||||
let mat_space = lerp_slice(space, ray_time).inverse();
|
||||
tri = (tri.0 * mat_space, tri.1 * mat_space, tri.2 * mat_space);
|
||||
mat_space
|
||||
} else {
|
||||
// Same transform for all rays
|
||||
if !is_cached {
|
||||
tri = (
|
||||
tri.0 * static_mat_space,
|
||||
tri.1 * static_mat_space,
|
||||
tri.2 * static_mat_space,
|
||||
);
|
||||
}
|
||||
static_mat_space
|
||||
if !space.is_empty() {
|
||||
tri.0 = tri.0 * mat_space;
|
||||
tri.1 = tri.1 * mat_space;
|
||||
tri.2 = tri.2 * mat_space;
|
||||
}
|
||||
} else {
|
||||
// No transforms
|
||||
Matrix4x4::new()
|
||||
|
||||
tri
|
||||
};
|
||||
|
||||
// Test ray against triangle
|
||||
|
@ -223,60 +236,72 @@ impl<'a> Surface for TriangleMesh<'a> {
|
|||
if rays.is_occlusion(ray_idx) {
|
||||
isects[ray_idx] = SurfaceIntersection::Occlude;
|
||||
rays.mark_done(ray_idx);
|
||||
break;
|
||||
} else {
|
||||
// Calculate intersection point and error magnitudes
|
||||
let (pos, pos_err) = triangle::surface_point(tri, (b0, b1, b2));
|
||||
|
||||
// Calculate geometric surface normal
|
||||
let geo_normal = cross(tri.0 - tri.1, tri.0 - tri.2).into_normal();
|
||||
|
||||
// Calculate interpolated surface normal, if any
|
||||
let shading_normal = if let Some(normals) = self.normals {
|
||||
let n0_slice = &normals[(tri_indices.0 as usize
|
||||
* self.time_sample_count)
|
||||
..((tri_indices.0 as usize + 1) * self.time_sample_count)];
|
||||
let n1_slice = &normals[(tri_indices.1 as usize
|
||||
* self.time_sample_count)
|
||||
..((tri_indices.1 as usize + 1) * self.time_sample_count)];
|
||||
let n2_slice = &normals[(tri_indices.2 as usize
|
||||
* self.time_sample_count)
|
||||
..((tri_indices.2 as usize + 1) * self.time_sample_count)];
|
||||
|
||||
let n0 = lerp_slice(n0_slice, ray_time).normalized();
|
||||
let n1 = lerp_slice(n1_slice, ray_time).normalized();
|
||||
let n2 = lerp_slice(n2_slice, ray_time).normalized();
|
||||
|
||||
let s_nor = ((n0 * b0) + (n1 * b1) + (n2 * b2)) * mat_space;
|
||||
if dot(s_nor, geo_normal) >= 0.0 {
|
||||
s_nor
|
||||
} else {
|
||||
-s_nor
|
||||
}
|
||||
} else {
|
||||
geo_normal
|
||||
};
|
||||
|
||||
let intersection_data = SurfaceIntersectionData {
|
||||
incoming: rays.dir(ray_idx),
|
||||
t: t,
|
||||
pos: pos,
|
||||
pos_err: pos_err,
|
||||
nor: shading_normal,
|
||||
nor_g: geo_normal,
|
||||
local_space: mat_space,
|
||||
sample_pdf: 0.0,
|
||||
};
|
||||
|
||||
// Fill in intersection data
|
||||
isects[ray_idx] = SurfaceIntersection::Hit {
|
||||
intersection_data: intersection_data,
|
||||
closure: shader.shade(&intersection_data, ray_time),
|
||||
};
|
||||
non_shadow_hit = true;
|
||||
rays.set_max_t(ray_idx, t);
|
||||
hit_tri = tri;
|
||||
hit_tri_indices = tri_indices;
|
||||
hit_tri_data = (t, b0, b1, b2);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate intersection data if necessary.
|
||||
if non_shadow_hit {
|
||||
let (t, b0, b1, b2) = hit_tri_data;
|
||||
|
||||
// Calculate intersection point and error magnitudes
|
||||
let (pos, pos_err) = triangle::surface_point(hit_tri, (b0, b1, b2));
|
||||
|
||||
// Calculate geometric surface normal
|
||||
let geo_normal =
|
||||
cross(hit_tri.0 - hit_tri.1, hit_tri.0 - hit_tri.2).into_normal();
|
||||
|
||||
// Calculate interpolated surface normal, if any
|
||||
let shading_normal = if let Some(normals) = self.normals {
|
||||
let n0_slice = &normals[(hit_tri_indices.0 as usize
|
||||
* self.time_sample_count)
|
||||
..((hit_tri_indices.0 as usize + 1) * self.time_sample_count)];
|
||||
let n1_slice = &normals[(hit_tri_indices.1 as usize
|
||||
* self.time_sample_count)
|
||||
..((hit_tri_indices.1 as usize + 1) * self.time_sample_count)];
|
||||
let n2_slice = &normals[(hit_tri_indices.2 as usize
|
||||
* self.time_sample_count)
|
||||
..((hit_tri_indices.2 as usize + 1) * self.time_sample_count)];
|
||||
|
||||
let n0 = lerp_slice(n0_slice, ray_time).normalized();
|
||||
let n1 = lerp_slice(n1_slice, ray_time).normalized();
|
||||
let n2 = lerp_slice(n2_slice, ray_time).normalized();
|
||||
|
||||
let s_nor = ((n0 * b0) + (n1 * b1) + (n2 * b2)) * mat_space;
|
||||
if dot(s_nor, geo_normal) >= 0.0 {
|
||||
s_nor
|
||||
} else {
|
||||
-s_nor
|
||||
}
|
||||
} else {
|
||||
geo_normal
|
||||
};
|
||||
|
||||
let intersection_data = SurfaceIntersectionData {
|
||||
incoming: rays.dir(ray_idx),
|
||||
t: t,
|
||||
pos: pos,
|
||||
pos_err: pos_err,
|
||||
nor: shading_normal,
|
||||
nor_g: geo_normal,
|
||||
local_space: mat_space,
|
||||
sample_pdf: 0.0,
|
||||
};
|
||||
|
||||
// Fill in intersection data
|
||||
isects[ray_idx] = SurfaceIntersection::Hit {
|
||||
intersection_data: intersection_data,
|
||||
closure: shader.shade(&intersection_data, ray_time),
|
||||
};
|
||||
}
|
||||
});
|
||||
ray_stack.pop_task();
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user