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]
|
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 {
|
pub fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> bool {
|
||||||
self.hit_simd(r, t_min, t_max)
|
self.hit_simd(r, t_min, t_max)
|
||||||
//self.hit_naive(r, t_min, t_max)
|
//self.hit_naive(r, t_min, t_max)
|
||||||
@ -152,7 +154,7 @@ impl AABB {
|
|||||||
unsafe {
|
unsafe {
|
||||||
use std::arch::x86_64::*;
|
use std::arch::x86_64::*;
|
||||||
let o4 = _mm_set_ps(0., r.origin.z, r.origin.y, r.origin.x);
|
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 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 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.));
|
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 vmin4 = _mm_min_ps(t1, t2);
|
||||||
let vmax4: (f32, f32, f32, f32) = std::mem::transmute(vmax4);
|
let vmax4: (f32, f32, f32, f32) = std::mem::transmute(vmax4);
|
||||||
let vmin4: (f32, f32, f32, f32) = std::mem::transmute(vmin4);
|
let vmin4: (f32, f32, f32, f32) = std::mem::transmute(vmin4);
|
||||||
let tmax = min(vmax4.0, min(vmax4.1, vmax4.2));
|
let tmax = min(min(vmax4.0, min(vmax4.1, vmax4.2)), t_max);
|
||||||
let tmin = max(vmin4.0, max(vmin4.1, vmin4.2));
|
let tmin = max(max(vmin4.0, max(vmin4.1, vmin4.2)), t_min);
|
||||||
//tmax >= tmin && tmin < r.time && tmax > t_min
|
tmin <= tmax
|
||||||
t_min <= tmin && tmin <= t_max
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,34 +210,91 @@ mod tests {
|
|||||||
|
|
||||||
macro_rules! hit_test {
|
macro_rules! hit_test {
|
||||||
($($name:ident,)*) => {
|
($($name:ident,)*) => {
|
||||||
mod hit {
|
$(
|
||||||
use super::*;
|
mod $name {
|
||||||
$(
|
use super::*;
|
||||||
#[test]
|
const T_MIN: f32 = 0.001;
|
||||||
fn $name() {
|
const T_MAX: f32 = f32::MAX;
|
||||||
let t_min = 0.001;
|
|
||||||
let t_max = f32::MAX;
|
fn test_bb() -> AABB {
|
||||||
let bb = AABB::new([1., -1., -1.], [3., 1., 1.]);
|
AABB::new([-1., -1., -1.], [1., 1., 1.])
|
||||||
// Hit
|
|
||||||
let r = Ray::new([0., 0., 0.], [1., 0., 0.], 0.5);
|
|
||||||
assert!(bb.$name(r, t_min, t_max));
|
|
||||||
}
|
}
|
||||||
)*
|
|
||||||
}
|
|
||||||
mod miss {
|
|
||||||
use super::*;
|
|
||||||
$(
|
|
||||||
#[test]
|
#[test]
|
||||||
fn $name() {
|
fn hit_front() {
|
||||||
let t_min = 0.001;
|
let bb = test_bb();
|
||||||
let t_max = f32::MAX;
|
let r = Ray::new([-2., 0., 0.], [1., 0., 0.], 0.5);
|
||||||
let bb = AABB::new([1., -1., -1.], [3., 1., 1.]);
|
assert!(bb.$name(r, T_MIN, T_MAX));
|
||||||
// Miss
|
|
||||||
let r = Ray::new([0., 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 origin: Vec3,
|
||||||
pub direction: Vec3,
|
pub direction: Vec3,
|
||||||
pub time: f32,
|
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 inv_direction: Vec3,
|
||||||
pub sign: [usize; 3],
|
pub sign: [usize; 3],
|
||||||
}
|
}
|
||||||
@ -14,7 +17,7 @@ impl Ray {
|
|||||||
where
|
where
|
||||||
V: Into<Vec3>,
|
V: Into<Vec3>,
|
||||||
{
|
{
|
||||||
let direction = direction.into();
|
let direction: Vec3 = direction.into();
|
||||||
let origin = origin.into();
|
let origin = origin.into();
|
||||||
let inv = 1. / direction;
|
let inv = 1. / direction;
|
||||||
Ray {
|
Ray {
|
||||||
|
|||||||
@ -41,7 +41,9 @@ pub fn new(opt: &Opt) -> Scene {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let stl_cube = STL::parse(
|
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,
|
false,
|
||||||
)
|
)
|
||||||
.expect("failed to parse cube");
|
.expect("failed to parse cube");
|
||||||
@ -106,7 +108,8 @@ pub fn new(opt: &Opt) -> Scene {
|
|||||||
&stl_cube,
|
&stl_cube,
|
||||||
Lambertian::new(ConstantTexture::new(Vec3::new(0.6, 0.6, 0.6))),
|
Lambertian::new(ConstantTexture::new(Vec3::new(0.6, 0.6, 0.6))),
|
||||||
),
|
),
|
||||||
200.,
|
//1.,
|
||||||
|
250.,
|
||||||
)),
|
)),
|
||||||
];
|
];
|
||||||
let world: Box<dyn Hit> = if opt.use_accel {
|
let world: Box<dyn Hit> = if opt.use_accel {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user