Fix AABB::hit_simd. Add comprehensive AABB hit testing.

This commit is contained in:
Bill Thiede 2023-01-28 10:38:09 -08:00
parent 2d696932e3
commit 5c2786a54d
3 changed files with 97 additions and 33 deletions

View File

@ -71,6 +71,8 @@ impl AABB {
self.bounds[1]
}
// TODO(wathiede): implement branchless https://tavianator.com/cgit/dimension.git/tree/libdimension/bvh/bvh.c#n194
pub fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> bool {
self.hit_simd(r, t_min, t_max)
//self.hit_naive(r, t_min, t_max)
@ -152,7 +154,7 @@ impl AABB {
unsafe {
use std::arch::x86_64::*;
let o4 = _mm_set_ps(0., r.origin.z, r.origin.y, r.origin.x);
let d4 = _mm_set_ps(0., r.direction.z, r.direction.y, r.direction.x);
let d4 = _mm_set_ps(0., r.inv_direction.z, r.inv_direction.y, r.inv_direction.x);
let bmin4 = _mm_set_ps(0., self.min().z, self.min().y, self.min().x);
let bmax4 = _mm_set_ps(0., self.max().z, self.max().y, self.max().x);
let mask4 = _mm_cmpeq_ps(_mm_setzero_ps(), _mm_set_ps(1., 0., 0., 0.));
@ -162,10 +164,9 @@ impl AABB {
let vmin4 = _mm_min_ps(t1, t2);
let vmax4: (f32, f32, f32, f32) = std::mem::transmute(vmax4);
let vmin4: (f32, f32, f32, f32) = std::mem::transmute(vmin4);
let tmax = min(vmax4.0, min(vmax4.1, vmax4.2));
let tmin = max(vmin4.0, max(vmin4.1, vmin4.2));
//tmax >= tmin && tmin < r.time && tmax > t_min
t_min <= tmin && tmin <= t_max
let tmax = min(min(vmax4.0, min(vmax4.1, vmax4.2)), t_max);
let tmin = max(max(vmin4.0, max(vmin4.1, vmin4.2)), t_min);
tmin <= tmax
}
}
@ -209,34 +210,91 @@ mod tests {
macro_rules! hit_test {
($($name:ident,)*) => {
mod hit {
use super::*;
$(
#[test]
fn $name() {
let t_min = 0.001;
let t_max = f32::MAX;
let bb = AABB::new([1., -1., -1.], [3., 1., 1.]);
// Hit
let r = Ray::new([0., 0., 0.], [1., 0., 0.], 0.5);
assert!(bb.$name(r, t_min, t_max));
$(
mod $name {
use super::*;
const T_MIN: f32 = 0.001;
const T_MAX: f32 = f32::MAX;
fn test_bb() -> AABB {
AABB::new([-1., -1., -1.], [1., 1., 1.])
}
)*
}
mod miss {
use super::*;
$(
#[test]
fn $name() {
let t_min = 0.001;
let t_max = f32::MAX;
let bb = AABB::new([1., -1., -1.], [3., 1., 1.]);
// Miss
let r = Ray::new([0., 0., 0.], [-1., 0., 0.], 0.5);
assert!(!bb.$name(r, t_min, t_max));
fn hit_front() {
let bb = test_bb();
let r = Ray::new([-2., 0., 0.], [1., 0., 0.], 0.5);
assert!(bb.$name(r, T_MIN, T_MAX));
}
)*
}
#[test]
fn hit_back() {
let bb = test_bb();
let r = Ray::new([2., 0., 0.], [-1., 0., 0.], 0.5);
assert!(bb.$name(r, T_MIN, T_MAX));
}
#[test]
fn hit_top() {
let bb = test_bb();
let r = Ray::new([0., 2., 0.], [0., -1., 0.], 0.5);
assert!(bb.$name(r, T_MIN, T_MAX));
}
#[test]
fn hit_bottom() {
let bb = test_bb();
let r = Ray::new([0., -2., 0.], [0., 1., 0.], 0.5);
assert!(bb.$name(r, T_MIN, T_MAX));
}
#[test]
fn hit_left() {
let bb = test_bb();
let r = Ray::new([0., 0., -2.], [0., 0., 1.], 0.5);
assert!(bb.$name(r, T_MIN, T_MAX));
}
#[test]
fn hit_right() {
let bb = test_bb();
let r = Ray::new([0., 0., 2.], [0., 0., -1.], 0.5);
assert!(bb.$name(r, T_MIN, T_MAX));
}
#[test]
fn miss_front() {
let bb = test_bb();
let r = Ray::new([0., 1.1, -1.1], [0., -1., 0.], 0.5);
assert!(!bb.$name(r, T_MIN, T_MAX));
}
#[test]
fn miss_back() {
let bb = test_bb();
let r = Ray::new([0., 1.1, 1.1], [0., -1., 0.], 0.5);
assert!(!bb.$name(r, T_MIN, T_MAX));
}
#[test]
fn miss_top() {
let bb = test_bb();
let r = Ray::new([0., 1.1, -1.1], [0., 0., 1.], 0.5);
assert!(!bb.$name(r, T_MIN, T_MAX));
}
#[test]
fn miss_bottom() {
let bb = test_bb();
let r = Ray::new([0., -1.1, -1.1], [0., 0., 1.], 0.5);
assert!(!bb.$name(r, T_MIN, T_MAX));
}
#[test]
fn miss_left() {
let bb = test_bb();
let r = Ray::new([-1.1, 0., -1.1], [0., 0., 1.], 0.5);
assert!(!bb.$name(r, T_MIN, T_MAX));
}
#[test]
fn miss_right() {
let bb = test_bb();
let r = Ray::new([1.1, 0., -1.1], [0., 0., 1.], 0.5);
assert!(!bb.$name(r, T_MIN, T_MAX));
}
}
)*
}
}

View File

@ -5,6 +5,9 @@ pub struct Ray {
pub origin: Vec3,
pub direction: Vec3,
pub time: f32,
// Precache 1/direction, a single ray intersects multiple AABB's, and divides are more
// expensive than multiplies.
pub inv_direction: Vec3,
pub sign: [usize; 3],
}
@ -14,7 +17,7 @@ impl Ray {
where
V: Into<Vec3>,
{
let direction = direction.into();
let direction: Vec3 = direction.into();
let origin = origin.into();
let inv = 1. / direction;
Ray {

View File

@ -41,7 +41,9 @@ pub fn new(opt: &Opt) -> Scene {
};
let stl_cube = STL::parse(
BufReader::new(Cursor::new(include_bytes!("../../stls/20mm cube.stl"))),
BufReader::new(Cursor::new(include_bytes!(
"../../stls/stanford_dragon-lowres.stl"
))),
false,
)
.expect("failed to parse cube");
@ -106,7 +108,8 @@ pub fn new(opt: &Opt) -> Scene {
&stl_cube,
Lambertian::new(ConstantTexture::new(Vec3::new(0.6, 0.6, 0.6))),
),
200.,
//1.,
250.,
)),
];
let world: Box<dyn Hit> = if opt.use_accel {