Add BVH bounding boxes missing files
This commit is contained in:
parent
dbb0ab2b91
commit
93cbb67b39
63
src/aabb.rs
Normal file
63
src/aabb.rs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
use crate::vec3::{Point3};
|
||||||
|
use crate::ray::{Ray};
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
|
#[derive(Copy, Debug, Clone)]
|
||||||
|
pub struct Aabb {
|
||||||
|
pub minimum: Point3,
|
||||||
|
pub maximum: Point3,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Aabb {
|
||||||
|
pub fn min(&self) -> Point3 { self.minimum }
|
||||||
|
pub fn max(&self) -> Point3 { self.maximum }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Aabb {
|
||||||
|
fn default() -> Self {
|
||||||
|
Aabb {minimum: Point3::default(), maximum: Point3::default() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//impl Hittable for Aabb {
|
||||||
|
impl Aabb {
|
||||||
|
pub fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> bool {
|
||||||
|
let mut t_min = t_min;
|
||||||
|
let mut t_max = t_max;
|
||||||
|
for a in 0..3 {
|
||||||
|
/*
|
||||||
|
let t0 = ((self.minimum[a] - ray.origin()[a]) / ray.direction()[a])
|
||||||
|
.min((self.maximum[a] - ray.origin()[a]) / ray.direction()[a]);
|
||||||
|
let t1 = ((self.minimum[a] - ray.origin()[a]) / ray.direction()[a])
|
||||||
|
.max((self.maximum[a] - ray.origin()[a]) / ray.direction()[a]);
|
||||||
|
t_min = t0.min(t_min);
|
||||||
|
t_max = t1.max(t_max);
|
||||||
|
if t_max <= t_min {
|
||||||
|
return false;
|
||||||
|
}*/
|
||||||
|
let inv_d = 1.0 / ray.direction()[a];
|
||||||
|
let mut t0 = (self.minimum[a] - ray.origin()[a]) * inv_d;
|
||||||
|
let mut t1 = (self.maximum[a] - ray.origin()[a]) * inv_d;
|
||||||
|
if inv_d < 0.0 {
|
||||||
|
mem::swap(&mut t0, &mut t1);
|
||||||
|
}
|
||||||
|
t_min = t_min.max(t0);
|
||||||
|
t_max = t_max.min(t1);
|
||||||
|
if t_max <= t_min {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
pub fn surrounding(&self, other: &Aabb) -> Aabb {
|
||||||
|
let minimum = Point3::new(
|
||||||
|
self.minimum.x().min(other.minimum.x()),
|
||||||
|
self.minimum.y().min(other.minimum.y()),
|
||||||
|
self.minimum.y().min(other.minimum.z()));
|
||||||
|
let maximum = Point3::new(
|
||||||
|
self.maximum.x().max(other.maximum.x()),
|
||||||
|
self.maximum.y().max(other.maximum.y()),
|
||||||
|
self.maximum.y().max(other.maximum.z()));
|
||||||
|
Aabb {minimum, maximum}
|
||||||
|
}
|
||||||
|
}
|
96
src/bvh.rs
Normal file
96
src/bvh.rs
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
use crate::hittable::{HittableList, Hittable, HitRecord};
|
||||||
|
use crate::aabb::Aabb;
|
||||||
|
use std::cmp;
|
||||||
|
use crate::Ray;
|
||||||
|
|
||||||
|
// https://github.com/fralken/ray-tracing-the-next-week/blob/master/src/bvh.rs
|
||||||
|
|
||||||
|
enum BVHNode {
|
||||||
|
Branch { left: Box<BVH>, right: Box<BVH> },
|
||||||
|
Leaf(Box<dyn Hittable>)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BVH {
|
||||||
|
tree: BVHNode,
|
||||||
|
bounding_box: Aabb
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BVH {
|
||||||
|
pub fn new(mut objects: HittableList, time0: f64, time1: f64) -> Self {
|
||||||
|
fn box_compare(time0: f64, time1: f64, axis: usize) -> impl FnMut(&Box<dyn Hittable + Sync>, &Box<dyn Hittable + Sync>) -> cmp::Ordering {
|
||||||
|
move |a, b| {
|
||||||
|
let a_bbox = a.bounding_box(time0, time1);
|
||||||
|
let b_bbox = b.bounding_box(time0, time1);
|
||||||
|
if let (Some(a), Some(b)) = (a_bbox, b_bbox) {
|
||||||
|
let ac = a.min()[axis] + a.max()[axis];
|
||||||
|
let bc = b.min()[axis] + b.max()[axis];
|
||||||
|
ac.partial_cmp(&bc).unwrap()
|
||||||
|
} else {
|
||||||
|
panic!("no bounding box in bvh node")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn axis_range(objects: &HittableList, time0: f64, time1: f64, axis: usize) -> f64 {
|
||||||
|
let (min, max) = objects.iter().fold((f64::MAX, f64::MIN), |(bmin, bmax), hit| {
|
||||||
|
if let Some(aabb) = hit.bounding_box(time0, time1) {
|
||||||
|
(bmin.min(aabb.min()[axis]), bmax.max(aabb.max()[axis]))
|
||||||
|
} else {
|
||||||
|
(bmin, bmax)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
max - min
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut axis_ranges: Vec<(usize, f64)> = (0..3)
|
||||||
|
.map(|a| (a, axis_range(&objects, time0, time1, a)))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
axis_ranges.sort_unstable_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
|
||||||
|
|
||||||
|
let axis = axis_ranges[0].0;
|
||||||
|
|
||||||
|
objects.sort_unstable_by(box_compare(time0, time1, axis));
|
||||||
|
let len = objects.len();
|
||||||
|
match len {
|
||||||
|
0 => panic!("no elements in scene"),
|
||||||
|
1 => {
|
||||||
|
let leaf = objects.pop().unwrap();
|
||||||
|
if let Some(bounding_box) = leaf.bounding_box(time0, time1) {
|
||||||
|
BVH { tree: BVHNode::Leaf(leaf), bounding_box }
|
||||||
|
} else {
|
||||||
|
panic!("no bounding box in bvh node")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
let right = BVH::new(objects.drain(len / 2..).collect(), time0, time1);
|
||||||
|
let left = BVH::new(objects, time0, time1);
|
||||||
|
let bounding_box = left.bounding_box.surrounding(&right.bounding_box);
|
||||||
|
BVH { tree: BVHNode::Branch { left: Box::new(left), right: Box::new(right) }, bounding_box }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hittable for BVH {
|
||||||
|
fn hit(&self, ray: &Ray, t_min: f64, mut t_max: f64) -> Option<HitRecord> {
|
||||||
|
if !self.bounding_box.hit(ray, t_min, t_max) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
match &self.tree {
|
||||||
|
BVHNode::Leaf(leaf) => leaf.hit(ray, t_min, t_max),
|
||||||
|
BVHNode::Branch { left, right } => {
|
||||||
|
let hit_left = left.hit(ray, t_min, t_max);
|
||||||
|
if let Some(hl) = &hit_left { t_max = hl.t };
|
||||||
|
let hit_right = right.hit(ray, t_min, t_max);
|
||||||
|
match hit_left {
|
||||||
|
Some(hit_left) => Some(hit_left),
|
||||||
|
_ => hit_right
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn bounding_box(&self, time0: f64, time1: f64) -> Option<Aabb> {
|
||||||
|
Some(self.bounding_box)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user