bvh: add some tests and fmt::Display implementations.
This commit is contained in:
parent
11a7cc6f08
commit
4a9754dfdb
@ -1,12 +1,20 @@
|
|||||||
|
use std::fmt;
|
||||||
|
|
||||||
use ray::Ray;
|
use ray::Ray;
|
||||||
use vec3::Vec3;
|
use vec3::Vec3;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct AABB {
|
pub struct AABB {
|
||||||
pub min: Vec3,
|
pub min: Vec3,
|
||||||
pub max: Vec3,
|
pub max: Vec3,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for AABB {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "({})-({})", self.min, self.max)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl AABB {
|
impl AABB {
|
||||||
pub fn new(min: Vec3, max: Vec3) -> AABB {
|
pub fn new(min: Vec3, max: Vec3) -> AABB {
|
||||||
AABB { min, max }
|
AABB { min, max }
|
||||||
|
|||||||
@ -94,7 +94,7 @@ fn random_scene() -> Vec<Box<Hit>> {
|
|||||||
objects
|
objects
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_scene_book(opt: &Opt) -> Scene {
|
fn build_scene_book(bvh: bool, opt: &Opt) -> Scene {
|
||||||
let lookfrom = Vec3::new(13., 2., 3.);
|
let lookfrom = Vec3::new(13., 2., 3.);
|
||||||
let lookat = Vec3::new(0., 0., 0.);
|
let lookat = Vec3::new(0., 0., 0.);
|
||||||
let dist_to_focus = 10.;
|
let dist_to_focus = 10.;
|
||||||
@ -112,7 +112,12 @@ fn build_scene_book(opt: &Opt) -> Scene {
|
|||||||
time_min,
|
time_min,
|
||||||
time_max,
|
time_max,
|
||||||
);
|
);
|
||||||
let world: Box<Hit> = Box::new(HitableList::new(random_scene()));
|
let world: Box<Hit>;
|
||||||
|
if bvh {
|
||||||
|
world = Box::new(BVH::new(random_scene(), time_min, time_max));
|
||||||
|
} else {
|
||||||
|
world = Box::new(HitableList::new(random_scene()));
|
||||||
|
}
|
||||||
Scene {
|
Scene {
|
||||||
camera,
|
camera,
|
||||||
world,
|
world,
|
||||||
@ -277,6 +282,7 @@ fn build_scene_cube(opt: &Opt) -> Scene {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Model {
|
pub enum Model {
|
||||||
Book,
|
Book,
|
||||||
|
BookBVH,
|
||||||
Tutorial,
|
Tutorial,
|
||||||
Cube,
|
Cube,
|
||||||
BVH,
|
BVH,
|
||||||
@ -296,6 +302,7 @@ impl str::FromStr for Model {
|
|||||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||||
match s {
|
match s {
|
||||||
"book" => Ok(Model::Book),
|
"book" => Ok(Model::Book),
|
||||||
|
"book_bvh" => Ok(Model::BookBVH),
|
||||||
"tutorial" => Ok(Model::Tutorial),
|
"tutorial" => Ok(Model::Tutorial),
|
||||||
"cube" => Ok(Model::Cube),
|
"cube" => Ok(Model::Cube),
|
||||||
"bvh" => Ok(Model::BVH),
|
"bvh" => Ok(Model::BVH),
|
||||||
@ -328,7 +335,8 @@ fn main() -> Result<(), std::io::Error> {
|
|||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let opt = Opt::from_args();
|
let opt = Opt::from_args();
|
||||||
let scene = match opt.model {
|
let scene = match opt.model {
|
||||||
Model::Book => build_scene_book(&opt),
|
Model::Book => build_scene_book(false, &opt),
|
||||||
|
Model::BookBVH => build_scene_book(true, &opt),
|
||||||
Model::Cube => build_scene_cube(&opt),
|
Model::Cube => build_scene_cube(&opt),
|
||||||
Model::Tutorial => build_scene_tutorial(&opt),
|
Model::Tutorial => build_scene_tutorial(&opt),
|
||||||
Model::BVH => build_scene_bvh(&opt),
|
Model::BVH => build_scene_bvh(&opt),
|
||||||
|
|||||||
111
rtiow/src/bvh.rs
111
rtiow/src/bvh.rs
@ -1,4 +1,5 @@
|
|||||||
use std;
|
use std;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
use rand;
|
use rand;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
@ -18,10 +19,30 @@ enum BVHNode {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for BVHNode {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
BVHNode::Leaf(ref hit) => write!(
|
||||||
|
f,
|
||||||
|
"Leaf: {}",
|
||||||
|
hit.bounding_box(0., 0.)
|
||||||
|
.map_or("NO BBOX".to_owned(), |bb| bb.to_string())
|
||||||
|
),
|
||||||
|
BVHNode::Branch { bbox, .. } => write!(
|
||||||
|
f,
|
||||||
|
"Branch: {}",
|
||||||
|
// TODO(wathiede): removing this .clone() results in a complaint about moving out
|
||||||
|
// of a borrow.
|
||||||
|
bbox.clone()
|
||||||
|
.map_or("NO BBOX".to_owned(), |bb| bb.to_string())
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn box_x_compare(ah: &Box<Hit>, bh: &Box<Hit>) -> std::cmp::Ordering {
|
fn box_x_compare(ah: &Box<Hit>, bh: &Box<Hit>) -> std::cmp::Ordering {
|
||||||
match (ah.bounding_box(0., 0.), bh.bounding_box(0., 0.)) {
|
match (ah.bounding_box(0., 0.), bh.bounding_box(0., 0.)) {
|
||||||
(Some(box_left), Some(box_right)) => {
|
(Some(box_left), Some(box_right)) => {
|
||||||
eprintln!("box_x_compare {} < {}", box_left.min, box_right.min);
|
|
||||||
return box_left.min.x.partial_cmp(&box_right.min.x).unwrap();
|
return box_left.min.x.partial_cmp(&box_right.min.x).unwrap();
|
||||||
}
|
}
|
||||||
_ => panic!("hit missing bounding box"),
|
_ => panic!("hit missing bounding box"),
|
||||||
@ -31,7 +52,6 @@ fn box_x_compare(ah: &Box<Hit>, bh: &Box<Hit>) -> std::cmp::Ordering {
|
|||||||
fn box_y_compare(ah: &Box<Hit>, bh: &Box<Hit>) -> std::cmp::Ordering {
|
fn box_y_compare(ah: &Box<Hit>, bh: &Box<Hit>) -> std::cmp::Ordering {
|
||||||
match (ah.bounding_box(0., 0.), bh.bounding_box(0., 0.)) {
|
match (ah.bounding_box(0., 0.), bh.bounding_box(0., 0.)) {
|
||||||
(Some(box_left), Some(box_right)) => {
|
(Some(box_left), Some(box_right)) => {
|
||||||
eprintln!("box_y_compare {} < {}", box_left.min, box_right.min);
|
|
||||||
return box_left.min.y.partial_cmp(&box_right.min.y).unwrap();
|
return box_left.min.y.partial_cmp(&box_right.min.y).unwrap();
|
||||||
}
|
}
|
||||||
_ => panic!("hit missing bounding box"),
|
_ => panic!("hit missing bounding box"),
|
||||||
@ -41,7 +61,6 @@ fn box_y_compare(ah: &Box<Hit>, bh: &Box<Hit>) -> std::cmp::Ordering {
|
|||||||
fn box_z_compare(ah: &Box<Hit>, bh: &Box<Hit>) -> std::cmp::Ordering {
|
fn box_z_compare(ah: &Box<Hit>, bh: &Box<Hit>) -> std::cmp::Ordering {
|
||||||
match (ah.bounding_box(0., 0.), bh.bounding_box(0., 0.)) {
|
match (ah.bounding_box(0., 0.), bh.bounding_box(0., 0.)) {
|
||||||
(Some(box_left), Some(box_right)) => {
|
(Some(box_left), Some(box_right)) => {
|
||||||
eprintln!("box_z_compare {} < {}", box_left.min, box_right.min);
|
|
||||||
return box_left.min.z.partial_cmp(&box_right.min.z).unwrap();
|
return box_left.min.z.partial_cmp(&box_right.min.z).unwrap();
|
||||||
}
|
}
|
||||||
_ => panic!("hit missing bounding box"),
|
_ => panic!("hit missing bounding box"),
|
||||||
@ -118,6 +137,7 @@ impl Hit for BVHNode {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bounding_box(&self, t_min: f32, t_max: f32) -> Option<AABB> {
|
fn bounding_box(&self, t_min: f32, t_max: f32) -> Option<AABB> {
|
||||||
match self {
|
match self {
|
||||||
BVHNode::Leaf(ref hit) => hit.bounding_box(t_min, t_max),
|
BVHNode::Leaf(ref hit) => hit.bounding_box(t_min, t_max),
|
||||||
@ -138,6 +158,23 @@ impl BVH {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn print_tree(f: &mut fmt::Formatter, depth: usize, bvhn: &BVHNode) -> fmt::Result {
|
||||||
|
// TODO(wathiede): recurse and indent
|
||||||
|
write!(f, "{}{}\n", " ".repeat(depth * 2), bvhn)?;
|
||||||
|
if let BVHNode::Branch { left, right, .. } = bvhn {
|
||||||
|
print_tree(f, depth + 1, left)?;
|
||||||
|
print_tree(f, depth + 1, right)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for BVH {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "Root\n")?;
|
||||||
|
print_tree(f, 1, &self.root)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Hit for BVH {
|
impl Hit for BVH {
|
||||||
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
|
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
|
||||||
self.root.hit(r, t_min, t_max)
|
self.root.hit(r, t_min, t_max)
|
||||||
@ -147,3 +184,71 @@ impl Hit for BVH {
|
|||||||
self.root.bounding_box(t_min, t_max)
|
self.root.bounding_box(t_min, t_max)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use aabb::AABB;
|
||||||
|
use material::Lambertian;
|
||||||
|
use material::Metal;
|
||||||
|
use sphere::Sphere;
|
||||||
|
use vec3::Vec3;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn bbox_two_spheres() {
|
||||||
|
let two_spheres_bvh = BVH::new(
|
||||||
|
vec![
|
||||||
|
Box::new(Sphere::new(
|
||||||
|
Vec3::new(0., 0., 0.),
|
||||||
|
0.5,
|
||||||
|
Box::new(Lambertian::new(Vec3::new(0.1, 0.2, 0.5))),
|
||||||
|
)),
|
||||||
|
Box::new(Sphere::new(
|
||||||
|
Vec3::new(1., 0., 0.),
|
||||||
|
0.5,
|
||||||
|
Box::new(Metal::new(Vec3::new(0.6, 0.6, 0.6), 0.2)),
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
0.,
|
||||||
|
1.,
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
AABB::new(Vec3::new(-0.5, -0.5, -0.5), Vec3::new(1.5, 0.5, 0.5)),
|
||||||
|
two_spheres_bvh.bounding_box(0., 1.).unwrap(),
|
||||||
|
"BVH:\n{}",
|
||||||
|
two_spheres_bvh
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn bbox_three_spheres() {
|
||||||
|
let three_spheres_bvh = BVH::new(
|
||||||
|
vec![
|
||||||
|
Box::new(Sphere::new(
|
||||||
|
Vec3::new(0., 0., 0.),
|
||||||
|
0.5,
|
||||||
|
Box::new(Lambertian::new(Vec3::new(0.1, 0.2, 0.5))),
|
||||||
|
)),
|
||||||
|
Box::new(Sphere::new(
|
||||||
|
Vec3::new(1., 0., 0.),
|
||||||
|
0.5,
|
||||||
|
Box::new(Metal::new(Vec3::new(0.6, 0.6, 0.6), 0.2)),
|
||||||
|
)),
|
||||||
|
Box::new(Sphere::new(
|
||||||
|
Vec3::new(0., 1., 0.),
|
||||||
|
0.5,
|
||||||
|
Box::new(Metal::new(Vec3::new(0.6, 0.6, 0.6), 0.2)),
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
0.,
|
||||||
|
1.,
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
AABB::new(Vec3::new(-0.5, -0.5, -0.5), Vec3::new(1.5, 1.5, 0.5)),
|
||||||
|
three_spheres_bvh.bounding_box(0., 1.).unwrap(),
|
||||||
|
"BVH:\n{}",
|
||||||
|
three_spheres_bvh
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user