rtiow: add aabb tests and benchmark along with terrible SIMD impl.
This commit is contained in:
@@ -2,7 +2,7 @@ use std::fmt;
|
||||
|
||||
use crate::{ray::Ray, vec3::Vec3};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
#[derive(Default, Debug, Copy, Clone, PartialEq)]
|
||||
pub struct AABB {
|
||||
bounds: [Vec3; 2],
|
||||
}
|
||||
@@ -30,7 +30,12 @@ fn max(x: f32, y: f32) -> f32 {
|
||||
}
|
||||
|
||||
impl AABB {
|
||||
pub fn new(min: Vec3, max: Vec3) -> AABB {
|
||||
pub fn new<V: Into<Vec3>>(min: V, max: V) -> AABB {
|
||||
let min: Vec3 = min.into();
|
||||
let max: Vec3 = max.into();
|
||||
assert!(min.x < max.x);
|
||||
assert!(min.y < max.y);
|
||||
assert!(min.z < max.z);
|
||||
AABB { bounds: [min, max] }
|
||||
}
|
||||
|
||||
@@ -61,10 +66,33 @@ impl AABB {
|
||||
pub fn min(&self) -> Vec3 {
|
||||
self.bounds[0]
|
||||
}
|
||||
|
||||
pub fn max(&self) -> Vec3 {
|
||||
self.bounds[1]
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
pub fn hit_naive(&self, r: Ray, t_min: f32, t_max: f32) -> bool {
|
||||
let mut t_min = t_min;
|
||||
let mut t_max = t_max;
|
||||
for axis in 0..3 {
|
||||
let t0 = ((self.min()[axis] - r.origin[axis]) * r.inv_direction[axis])
|
||||
.min((self.max()[axis] - r.origin[axis]) * r.inv_direction[axis]);
|
||||
let t1 = ((self.min()[axis] - r.origin[axis]) * r.inv_direction[axis])
|
||||
.max((self.max()[axis] - r.origin[axis]) * r.inv_direction[axis]);
|
||||
t_min = t0.max(t_min);
|
||||
t_max = t1.min(t_max);
|
||||
if t_max <= t_min {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub fn hit2(&self, r: Ray, t_min: f32, t_max: f32) -> bool {
|
||||
let mut t_min = t_min;
|
||||
let mut t_max = t_max;
|
||||
@@ -119,21 +147,26 @@ impl AABB {
|
||||
t_min < t1 && t_max > t0
|
||||
}
|
||||
|
||||
pub fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> bool {
|
||||
let mut t_min = t_min;
|
||||
let mut t_max = t_max;
|
||||
for axis in 0..3 {
|
||||
let t0 = ((self.min()[axis] - r.origin[axis]) * r.inv_direction[axis])
|
||||
.min((self.max()[axis] - r.origin[axis]) * r.inv_direction[axis]);
|
||||
let t1 = ((self.min()[axis] - r.origin[axis]) * r.inv_direction[axis])
|
||||
.max((self.max()[axis] - r.origin[axis]) * r.inv_direction[axis]);
|
||||
t_min = t0.max(t_min);
|
||||
t_max = t1.min(t_max);
|
||||
if t_max <= t_min {
|
||||
return false;
|
||||
}
|
||||
pub fn hit_simd(&self, r: Ray, t_min: f32, t_max: f32) -> bool {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
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 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.));
|
||||
let t1 = _mm_mul_ps(_mm_sub_ps(_mm_and_ps(bmin4, mask4), o4), d4);
|
||||
let t2 = _mm_mul_ps(_mm_sub_ps(_mm_and_ps(bmax4, mask4), o4), d4);
|
||||
let vmax4 = _mm_max_ps(t1, t2);
|
||||
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
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub fn hit_fast(&self, r: Ray, _t_min: f32, _t_max: f32) -> bool {
|
||||
@@ -169,3 +202,48 @@ pub fn surrounding_box(box0: &AABB, box1: &AABB) -> AABB {
|
||||
);
|
||||
AABB::new(min, max)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
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 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));
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hit_test! {
|
||||
hit_naive,
|
||||
hit2,
|
||||
hit_fast,
|
||||
hit_simd,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user