Fix AABB::hit_simd. Add comprehensive AABB hit testing.
This commit is contained in:
parent
2d696932e3
commit
5c2786a54d
@ -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));
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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 {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user