diff --git a/rtiow/src/aabb.rs b/rtiow/src/aabb.rs index 75ab914..98b8c9f 100644 --- a/rtiow/src/aabb.rs +++ b/rtiow/src/aabb.rs @@ -35,6 +35,30 @@ impl AABB { AABB { bounds: [min, max] } } + pub fn volume(&self) -> f32 { + (self.min().x - self.max().x).abs() + * (self.min().y - self.max().y).abs() + * (self.min().z - self.max().z).abs() + } + + pub fn longest_axis(&self) -> usize { + let xd = (self.min().x - self.max().x).abs(); + let yd = (self.min().y - self.max().y).abs(); + let zd = (self.min().z - self.max().z).abs(); + + if xd >= yd && xd >= zd { + return 0; + } + if yd >= xd && yd >= zd { + return 1; + } + return 2; + } + + pub fn mid_point(&self) -> Vec3 { + self.bounds[0] + (self.bounds[1] - self.bounds[0]) / 2. + } + pub fn min(&self) -> Vec3 { self.bounds[0] } @@ -64,7 +88,7 @@ impl AABB { true } - pub fn hit(&self, r: Ray, t0: f32, t1: f32) -> bool { + pub fn hit_precompute(&self, r: Ray, t0: f32, t1: f32) -> bool { let mut t_min = (self.bounds[r.sign[0]].x - r.origin.x) * r.inv_direction.x; let mut t_max = (self.bounds[1 - r.sign[0]].x - r.origin.x) * r.inv_direction.x; let t_y_min = (self.bounds[r.sign[0]].y - r.origin.y) * r.inv_direction.y; @@ -95,7 +119,7 @@ impl AABB { t_min < t1 && t_max > t0 } - pub fn hit_original(&self, r: Ray, t_min: f32, t_max: f32) -> bool { + 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 { diff --git a/rtiow/src/bin/tracer.rs b/rtiow/src/bin/tracer.rs index 7a828f4..c96adae 100644 --- a/rtiow/src/bin/tracer.rs +++ b/rtiow/src/bin/tracer.rs @@ -13,9 +13,7 @@ use cpuprofiler::PROFILER; use structopt::StructOpt; use rtiow::renderer::render; -use rtiow::renderer::Model; use rtiow::renderer::Opt; -use rtiow::scenes; fn main() -> Result<(), std::io::Error> { stderrlog::new() @@ -25,14 +23,7 @@ fn main() -> Result<(), std::io::Error> { .unwrap(); let start = Instant::now(); let opt = Opt::from_args(); - let scene = match opt.model { - Model::Book => scenes::book::new(false, &opt), - Model::Bench => scenes::bench::new(&opt), - Model::BookBVH => scenes::book::new(true, &opt), - Model::Cube => scenes::cube::new(&opt), - Model::Tutorial => scenes::tutorial::new(&opt), - Model::BVH => scenes::bvh::new(&opt), - }; + let scene = opt.model.scene(&opt); fs::create_dir_all(&opt.output)?; let pprof_path = "pprof.profile"; if opt.pprof { diff --git a/rtiow/src/bvh.rs b/rtiow/src/bvh.rs index 553e4cf..730cdef 100644 --- a/rtiow/src/bvh.rs +++ b/rtiow/src/bvh.rs @@ -68,16 +68,112 @@ fn box_z_compare(ah: &Box, bh: &Box) -> std::cmp::Ordering { } } +// Return the first element from the vector, which should be the only element. +// TODO(wathiede): we really want a .first_into() (.first() doesn't work because it +// returns a reference.) +fn vec_first_into(v: Vec) -> T { + if v.len() != 1 { + panic!(format!( + "vec_first_into called for vector length != 1, length {}", + v.len() + )); + } + for i in v.into_iter() { + return i; + } + panic!("Unreachable"); +} + +fn vec_split_into(v: Vec, offset: usize) -> (Vec, Vec) { + let mut left_half = Vec::new(); + let mut right_half = Vec::new(); + v.into_iter().enumerate().for_each(|(i, h)| { + if i < offset { + left_half.push(h); + } else { + right_half.push(h); + } + }); + (left_half, right_half) +} + impl BVHNode { - fn new(l: Vec>, t_min: f32, t_max: f32) -> BVHNode { - if l.len() == 1 { - // Return the first element from the vector, which should be the only element. - // TODO(wathiede): we really want a .first_into() (.first() doesn't work because it - // returns a reference.) - for h in l.into_iter() { - return BVHNode::Leaf(h); + fn new_sah(l: Vec>, t_min: f32, t_max: f32) -> BVHNode { + eprintln!("l.len() {}", l.len()); + let mut l: Vec> = l.into_iter().collect(); + let n = l.len(); + let main_box = + l[1..] + .iter() + .fold(l[0].bounding_box(t_min, t_max).unwrap(), |acc, h| { + match h.bounding_box(t_min, t_max) { + Some(new_box) => surrounding_box(&new_box, &acc), + None => panic!("hit without bounding box"), + } + }); + + let axis = main_box.longest_axis(); + match axis { + 0 => l.sort_by(box_x_compare), + 1 => l.sort_by(box_y_compare), + 2 => l.sort_by(box_z_compare), + val @ _ => panic!("unknown axis {}", val), + }; + let boxes: Vec<_> = l + .iter() + .map(|hit| hit.bounding_box(t_min, t_max).unwrap()) + .collect(); + + let mut left_area = Vec::with_capacity(n); + let mut left_box = boxes[0].clone(); + for i in 1..n - 1 { + left_box = surrounding_box(&left_box, &boxes[i]); + left_area[i] = left_box.volume(); + } + + let mut right_area = Vec::with_capacity(n); + right_area[n - 1] = boxes[n - 1].volume(); + let mut right_box = boxes[n - 1].clone(); + for i in (0..n - 2).rev() { + right_box = surrounding_box(&right_box, &boxes[i]); + right_area[i] = right_box.volume(); + } + + let mut min_sah = std::f32::MAX; + let mut min_sah_idx = 0; + for i in 0..n - 1 { + let sah = i as f32 * left_area[i] + (n - i - 1) as f32 * right_area[i + 1]; + if sah < min_sah { + min_sah_idx = i; + min_sah = sah; } - panic!("Unreachable"); + } + + let left: Box; + let right: Box; + if min_sah_idx == 0 { + let (l, r) = vec_split_into(l, 1); + left = Box::new(BVHNode::Leaf(vec_first_into(l))); + right = Box::new(BVHNode::new_sah(r, t_min, t_max)); + } else if min_sah_idx == n - 2 { + let (l, r) = vec_split_into(l, min_sah_idx + 1); + left = Box::new(BVHNode::new_sah(l, t_min, t_max)); + right = Box::new(BVHNode::Leaf(vec_first_into(r))); + } else { + let (l, r) = vec_split_into(l, min_sah_idx + 1); + left = Box::new(BVHNode::new_sah(l, t_min, t_max)); + right = Box::new(BVHNode::new_sah(r, t_min, t_max)); + } + + BVHNode::Branch { + left, + right, + bbox: Some(main_box), + } + } + fn new_dumb(l: Vec>, t_min: f32, t_max: f32) -> BVHNode { + if l.len() == 1 { + return BVHNode::Leaf(vec_first_into(l)); } else { let mut l: Vec> = l.into_iter().collect(); let mut rng = rand::thread_rng(); @@ -88,18 +184,10 @@ impl BVHNode { val @ _ => panic!("unknown axis {}", val), } - let mut left_half = Vec::new(); - let mut right_half = Vec::new(); - let half_idx = l.len() / 2; - l.into_iter().enumerate().for_each(|(i, h)| { - if i < half_idx { - left_half.push(h); - } else { - right_half.push(h); - } - }); - let left = Box::new(BVHNode::new(left_half, t_min, t_max)); - let right = Box::new(BVHNode::new(right_half, t_min, t_max)); + let half = l.len() / 2; + let (left_half, right_half) = vec_split_into(l, half); + let left = Box::new(BVHNode::new_dumb(left_half, t_min, t_max)); + let right = Box::new(BVHNode::new_dumb(right_half, t_min, t_max)); let bbox = BVHNode::surrounding_box(left.as_ref(), right.as_ref(), t_min, t_max); return BVHNode::Branch { left, right, bbox }; } @@ -129,6 +217,7 @@ impl Hit for BVHNode { fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option { match self { BVHNode::Leaf(ref hit) => hit.hit(r, t_min, t_max), + // TODO(wathiede): call bbox.hit() before recursing down both paths of tree. BVHNode::Branch { ref left, ref right, @@ -163,7 +252,7 @@ impl BVH { let count = l.len(); let start = Instant::now(); let bvh = BVH { - root: BVHNode::new(l, t_min, t_max), + root: BVHNode::new_sah(l, t_min, t_max), }; let runtime = start.elapsed(); info!( diff --git a/rtiow/src/cube.rs b/rtiow/src/cube.rs index cceae83..5d59b98 100644 --- a/rtiow/src/cube.rs +++ b/rtiow/src/cube.rs @@ -25,6 +25,8 @@ impl Cube { impl Hit for Cube { fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option { + info!("Cube info"); + eprintln!("Cube eprintln"); // See if it hit the positive X wall first. let oc = r.origin - self.center; let a = dot(r.direction, r.direction); diff --git a/rtiow/src/kdtree.rs b/rtiow/src/kdtree.rs new file mode 100644 index 0000000..e36c8f0 --- /dev/null +++ b/rtiow/src/kdtree.rs @@ -0,0 +1,188 @@ +use std::fmt; + +use aabb::surrounding_box; +use aabb::AABB; +use hitable::Hit; +use hitable::HitRecord; +use ray::Ray; + +pub enum KDTree { + Leaf(Box), + Branch { + left: Box, + right: Box, + bbox: Option, + }, +} + +// Return the first element from the vector, which should be the only element. +// TODO(wathiede): we really want a .first_into() (.first() doesn't work because it +// returns a reference.) +fn vec_first_into(v: Vec) -> T { + if v.len() != 1 { + panic!(format!( + "vec_first_into called for vector length != 1, length {}", + v.len() + )); + } + for i in v.into_iter() { + return i; + } + panic!("Unreachable"); +} + +fn vec_split_into(v: Vec, offset: usize) -> (Vec, Vec) { + let mut left_half = Vec::new(); + let mut right_half = Vec::new(); + v.into_iter().enumerate().for_each(|(i, h)| { + if i < offset { + left_half.push(h); + } else { + right_half.push(h); + } + }); + (left_half, right_half) +} + +impl KDTree { + pub fn new(l: Vec>, t_min: f32, t_max: f32) -> KDTree { + if l.len() == 0 { + panic!("Attempt to build k-d tree with no Hit objects"); + } + + if l.len() == 1 { + return KDTree::Leaf(vec_first_into(l)); + } + + if l.len() == 2 { + let (left_vec, right_vec) = vec_split_into(l, 1); + let left = vec_first_into(left_vec); + let right = vec_first_into(right_vec); + let bbox = surrounding_box( + &left.bounding_box(t_min, t_max).unwrap(), + &right.bounding_box(t_min, t_max).unwrap(), + ); + return KDTree::Branch { + left: Box::new(KDTree::Leaf(left)), + right: Box::new(KDTree::Leaf(right)), + bbox: Some(bbox), + }; + } + let bbox = l[0].bounding_box(t_min, t_max).unwrap(); + let mut mid_point = bbox.mid_point(); + let bbox = l[1..].iter().fold(bbox, |acc, h| { + let new_bbox = &h.bounding_box(t_min, t_max).unwrap(); + mid_point = mid_point + new_bbox.mid_point(); + surrounding_box(&acc, new_bbox) + }); + mid_point = mid_point / l.len() as f32; + let axis = bbox.longest_axis(); + let mut left_half = Vec::new(); + let mut right_half = Vec::new(); + match axis { + 0 => l.into_iter().for_each(|h| { + if h.bounding_box(t_min, t_max).unwrap().mid_point().x < mid_point.x { + left_half.push(h); + } else { + right_half.push(h); + } + }), + 1 => l.into_iter().for_each(|h| { + if h.bounding_box(t_min, t_max).unwrap().mid_point().y < mid_point.y { + left_half.push(h); + } else { + right_half.push(h); + } + }), + 2 => l.into_iter().for_each(|h| { + if h.bounding_box(t_min, t_max).unwrap().mid_point().z < mid_point.z { + left_half.push(h); + } else { + right_half.push(h); + } + }), + _ => panic!("Unreachable"), + }; + KDTree::Branch { + left: Box::new(KDTree::new(left_half, t_min, t_max)), + right: Box::new(KDTree::new(right_half, t_min, t_max)), + bbox: Some(bbox), + } + } + + fn volume(&self) -> f32 { + let bbox = self.bounding_box(0., 0.).unwrap(); + (bbox.min().x - bbox.max().x).abs() + * (bbox.min().y - bbox.max().y).abs() + * (bbox.min().z - bbox.max().z).abs() + } +} + +fn print_tree(f: &mut fmt::Formatter, depth: usize, kdt: &KDTree) -> fmt::Result { + let vol = kdt.volume(); + write!(f, "{:8.2}{}", vol, " ".repeat(depth * 2))?; + match kdt { + KDTree::Leaf(ref hit) => write!( + f, + "Leaf: {}\n", + hit.bounding_box(0., 0.) + .map_or("NO BBOX".to_owned(), |bb| bb.to_string()) + )?, + KDTree::Branch { bbox, .. } => write!( + f, + "Branch: {}\n", + // 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()) + )?, + } + if let KDTree::Branch { left, right, .. } = kdt { + print_tree(f, depth + 1, left)?; + print_tree(f, depth + 1, right)?; + } + Ok(()) +} + +impl fmt::Display for KDTree { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "kd-tree\n")?; + print_tree(f, 1, &self) + } +} +impl Hit for KDTree { + fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option { + match self.bounding_box(t_min, t_max) { + Some(bbox) => if !bbox.hit(r, t_min, t_max) { + return None; + }, + None => { + info!("KDTree::hit no bbox: {:?}", r); + return None; + } + } + match self { + KDTree::Leaf(ref hit) => hit.hit(r, t_min, t_max), + KDTree::Branch { left, right, bbox } => match bbox { + None => None, + Some(_bbox) => match (left.hit(r, t_min, t_max), right.hit(r, t_min, t_max)) { + (Some(hit_left), Some(hit_right)) => if hit_left.t < hit_right.t { + return Some(hit_left); + } else { + return Some(hit_right); + }, + (Some(hit_left), None) => Some(hit_left), + (None, Some(hit_right)) => Some(hit_right), + (None, None) => None, + }, + }, + } + } + + fn bounding_box(&self, t_min: f32, t_max: f32) -> Option { + match self { + KDTree::Leaf(ref hit) => hit.bounding_box(t_min, t_max), + KDTree::Branch { bbox, .. } => bbox.clone(), + } + } +} diff --git a/rtiow/src/lib.rs b/rtiow/src/lib.rs index 9fc0b7f..d35501b 100644 --- a/rtiow/src/lib.rs +++ b/rtiow/src/lib.rs @@ -4,6 +4,7 @@ pub mod camera; pub mod cube; pub mod hitable; pub mod hitable_list; +pub mod kdtree; pub mod material; pub mod moving_sphere; pub mod ray; diff --git a/rtiow/src/ray.rs b/rtiow/src/ray.rs index 376c29f..c52450f 100644 --- a/rtiow/src/ray.rs +++ b/rtiow/src/ray.rs @@ -1,6 +1,6 @@ use vec3::Vec3; -#[derive(Copy, Clone, Default)] +#[derive(Copy, Clone, Debug, Default)] pub struct Ray { pub origin: Vec3, pub direction: Vec3, diff --git a/rtiow/src/renderer.rs b/rtiow/src/renderer.rs index 139861a..a285b21 100644 --- a/rtiow/src/renderer.rs +++ b/rtiow/src/renderer.rs @@ -16,16 +16,30 @@ use rand::Rng; use camera::Camera; use hitable::Hit; use ray::Ray; +use scenes; use vec3::Vec3; #[derive(Debug)] pub enum Model { Bench, Book, - BookBVH, Tutorial, Cube, BVH, + Test, +} + +impl Model { + pub fn scene(&self, opt: &Opt) -> Scene { + match self { + Model::Book => scenes::book::new(&opt), + Model::Bench => scenes::bench::new(&opt), + Model::Cube => scenes::cube::new(&opt), + Model::Tutorial => scenes::tutorial::new(&opt), + Model::BVH => scenes::bvh::new(&opt), + Model::Test => scenes::test::new(&opt), + } + } } #[derive(Debug)] @@ -43,10 +57,10 @@ impl str::FromStr for Model { match s { "bench" => Ok(Model::Bench), "book" => Ok(Model::Book), - "book_bvh" => Ok(Model::BookBVH), "tutorial" => Ok(Model::Tutorial), "cube" => Ok(Model::Cube), "bvh" => Ok(Model::BVH), + "test" => Ok(Model::Test), _ => Err(ModelParseError(s.to_owned())), } } @@ -56,18 +70,21 @@ impl str::FromStr for Model { #[structopt(name = "tracer", about = "An experimental ray tracer.")] pub struct Opt { /// Image width - #[structopt(short = "w", long = "width", default_value = "128")] + #[structopt(short = "w", long = "width", default_value = "1024")] pub width: usize, /// Image height - #[structopt(short = "h", long = "height", default_value = "128")] + #[structopt(short = "h", long = "height", default_value = "1024")] pub height: usize, /// Sub-samples per pixel #[structopt(short = "s", long = "subsample", default_value = "1")] pub subsamples: usize, - #[structopt(long = "model", default_value = "bench")] + #[structopt(long = "model", default_value = "test")] pub model: Model, #[structopt(long = "pprof")] pub pprof: bool, + /// Use acceleration data structure, may be BVH or kd-tree depending on scene. + #[structopt(long = "use_accel")] + pub use_accel: bool, /// Output directory #[structopt(parse(from_os_str), default_value = "/tmp/tracer")] diff --git a/rtiow/src/scenes/bench.rs b/rtiow/src/scenes/bench.rs index 60fa4a0..5eaccf2 100644 --- a/rtiow/src/scenes/bench.rs +++ b/rtiow/src/scenes/bench.rs @@ -1,10 +1,10 @@ use rand; use rand::Rng; -use bvh::BVH; use camera::Camera; use hitable::Hit; use hitable_list::HitableList; +use kdtree::KDTree; use material::Lambertian; use renderer::Opt; use renderer::Scene; @@ -12,7 +12,7 @@ use sphere::Sphere; use vec3::Vec3; pub fn new(opt: &Opt) -> Scene { - let lookfrom = Vec3::new(0.01, 20., 0.); + let lookfrom = Vec3::new(20., 20., 20.); let lookat = Vec3::new(0., 0., 0.); let dist_to_focus = (lookfrom - lookat).length(); let aperture = 0.1; @@ -31,7 +31,7 @@ pub fn new(opt: &Opt) -> Scene { ); let mut rng = rand::thread_rng(); let mut grid: Vec> = Vec::new(); - let len = 30; + let len = 100; for x in 0..len { for z in 0..len { let r = rng.gen_range::(0., 1.); @@ -45,12 +45,12 @@ pub fn new(opt: &Opt) -> Scene { ))); } } - let use_bvh = false; + let use_kdtree = true; let world: Box; - if use_bvh { - let bvh = BVH::new(grid, time_min, time_max); - trace!(target: "bvh", "World {}", bvh); - world = Box::new(bvh); + if use_kdtree { + let kdtree = KDTree::new(grid, time_min, time_max); + //trace!(target: "k-d tree", "World {}", kdtree); + world = Box::new(kdtree); } else { world = Box::new(HitableList::new(grid)); } diff --git a/rtiow/src/scenes/book.rs b/rtiow/src/scenes/book.rs index df7f9f8..5fcdfb3 100644 --- a/rtiow/src/scenes/book.rs +++ b/rtiow/src/scenes/book.rs @@ -5,6 +5,7 @@ use bvh::BVH; use camera::Camera; use hitable::Hit; use hitable_list::HitableList; +use kdtree::KDTree; use material::Dielectric; use material::Lambertian; use material::Metal; @@ -13,7 +14,7 @@ use renderer::Scene; use sphere::Sphere; use vec3::Vec3; -pub fn new(bvh: bool, opt: &Opt) -> Scene { +pub fn new(opt: &Opt) -> Scene { let lookfrom = Vec3::new(13., 2., 3.); let lookat = Vec3::new(0., 0., 0.); let dist_to_focus = 10.; @@ -31,14 +32,16 @@ pub fn new(bvh: bool, opt: &Opt) -> Scene { time_min, time_max, ); - let world: Box; - if bvh { - let b = BVH::new(random_scene(), time_min, time_max); - trace!(target: "bvh", "World {}", b); - world = Box::new(b); + let ground_color = if opt.use_accel { + Vec3::new(1.0, 0.4, 0.4) } else { - world = Box::new(HitableList::new(random_scene())); - } + Vec3::new(0.4, 1.0, 0.4) + }; + let world: Box = if opt.use_accel { + Box::new(KDTree::new(random_scene(ground_color), time_min, time_max)) + } else { + Box::new(HitableList::new(random_scene(ground_color))) + }; Scene { camera, world, @@ -48,12 +51,12 @@ pub fn new(bvh: bool, opt: &Opt) -> Scene { } } -fn random_scene() -> Vec> { +fn random_scene(background_color: Vec3) -> Vec> { let mut rng = rand::thread_rng(); let mut objects: Vec> = vec![Box::new(Sphere::new( Vec3::new(0., -1000., 0.), 1000., - Box::new(Lambertian::new(Vec3::new(0.5, 0.5, 0.5))), + Box::new(Lambertian::new(background_color)), ))]; let mut random = || rng.gen_range::(0., 1.); diff --git a/rtiow/src/scenes/mod.rs b/rtiow/src/scenes/mod.rs index 54194a3..ebccd6f 100644 --- a/rtiow/src/scenes/mod.rs +++ b/rtiow/src/scenes/mod.rs @@ -2,4 +2,5 @@ pub mod bench; pub mod book; pub mod bvh; pub mod cube; +pub mod test; pub mod tutorial; diff --git a/rtiow/src/scenes/test.rs b/rtiow/src/scenes/test.rs new file mode 100644 index 0000000..0a5cea3 --- /dev/null +++ b/rtiow/src/scenes/test.rs @@ -0,0 +1,80 @@ +use std::f32::consts::PI; + +use rand; +use rand::Rng; + +use camera::Camera; +use hitable::Hit; +use hitable_list::HitableList; +use kdtree::KDTree; +use material::Lambertian; +use material::Metal; +use renderer::Opt; +use renderer::Scene; +use sphere::Sphere; +use vec3::Vec3; + +pub fn new(opt: &Opt) -> Scene { + let lookfrom = Vec3::new(0.001, 0.001, 20.); + let lookat = Vec3::new(0., 0., 0.); + let dist_to_focus = (lookfrom - lookat).length(); + let aperture = 0.1; + let time_min = 0.; + let time_max = 0.; + let camera = Camera::new( + lookfrom, + lookat, + Vec3::new(0., 1., 0.), + 45., + opt.width as f32 / opt.height as f32, + aperture, + dist_to_focus, + time_min, + time_max, + ); + let mut objects: Vec> = vec![Box::new(Sphere::new( + Vec3::new(0., 0., 0.), + 5., + Box::new(Metal::new(Vec3::new(0.5, 0.5, 0.5), 0.)), + ))]; + let num_spheres = 6; + let radius = 7.; + let mut rng = rand::thread_rng(); + let mut random = || rng.gen_range::(0., 1.); + for i in 0..num_spheres { + let c1 = radius * ((2. * PI) * (i as f32 / num_spheres as f32)).sin(); + let c2 = radius * ((2. * PI) * (i as f32 / num_spheres as f32)).cos(); + let center = Vec3::new(0., c1, c2); + objects.push(Box::new(Sphere::new( + center, + 0.5, + Box::new(Lambertian::new(Vec3::new(1., 0., 0.))), + ))); + let center = Vec3::new(c1, 0., c2); + objects.push(Box::new(Sphere::new( + center, + 0.5, + Box::new(Lambertian::new(Vec3::new(0., 1., 0.))), + ))); + let center = Vec3::new(c1, c2, 0.); + objects.push(Box::new(Sphere::new( + center, + 0.5, + Box::new(Lambertian::new(Vec3::new(0., 0., 1.))), + ))); + } + let world: Box = if opt.use_accel { + let kd = KDTree::new(objects, time_min, time_max); + //println!("{}", kd); + Box::new(kd) + } else { + Box::new(HitableList::new(objects)) + }; + Scene { + camera, + world, + subsamples: opt.subsamples, + width: opt.width, + height: opt.height, + } +} diff --git a/rtiow/src/scenes/tutorial.rs b/rtiow/src/scenes/tutorial.rs index e4ebcc7..3cf7cf1 100644 --- a/rtiow/src/scenes/tutorial.rs +++ b/rtiow/src/scenes/tutorial.rs @@ -1,6 +1,7 @@ use camera::Camera; use hitable::Hit; use hitable_list::HitableList; +use kdtree::KDTree; use material::Lambertian; use material::Metal; use moving_sphere::MovingSphere; @@ -15,7 +16,7 @@ pub fn new(opt: &Opt) -> Scene { let dist_to_focus = (lookfrom - lookat).length(); let aperture = 0.1; let time_min = 0.; - let time_max = 1.; + let time_max = 0.; let camera = Camera::new( lookfrom, lookat, @@ -27,7 +28,14 @@ pub fn new(opt: &Opt) -> Scene { time_min, time_max, ); - let world: Box = Box::new(HitableList::new(vec![ + let ground_color = if opt.use_accel { + Vec3::new(1.0, 0.4, 0.4) + } else { + Vec3::new(0.4, 1.0, 0.4) + }; + + let objects: Vec> = vec![ + //let world: Box = Box::new(HitableList::new(vec![ Box::new(Sphere::new( Vec3::new(0., 0., -1.), 0.5, @@ -36,7 +44,7 @@ pub fn new(opt: &Opt) -> Scene { Box::new(Sphere::new( Vec3::new(0., -100.5, -1.), 100., - Box::new(Lambertian::new(Vec3::new(0.8, 0.8, 0.8))), + Box::new(Lambertian::new(ground_color)), )), Box::new(Sphere::new( Vec3::new(1., 0., -1.), @@ -51,7 +59,12 @@ pub fn new(opt: &Opt) -> Scene { 1., Box::new(Lambertian::new(Vec3::new(0.2, 0.8, 0.2))), )), - ])); + ]; + let world: Box = if opt.use_accel { + Box::new(KDTree::new(objects, time_min, time_max)) + } else { + Box::new(HitableList::new(objects)) + }; Scene { camera, world,