Implement kd-tree.
Add simple test scene. Failed attempt to make BVH faster. Failed attempt to implement SAH w/ BVH. Failed attempt to make AABB::hit faster.
This commit is contained in:
parent
54f1304695
commit
2104f1a76c
@ -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 {
|
||||
|
||||
@ -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 {
|
||||
|
||||
131
rtiow/src/bvh.rs
131
rtiow/src/bvh.rs
@ -68,16 +68,112 @@ fn box_z_compare(ah: &Box<Hit>, bh: &Box<Hit>) -> 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<T>(v: Vec<T>) -> 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<T>(v: Vec<T>, offset: usize) -> (Vec<T>, Vec<T>) {
|
||||
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<Box<Hit>>, 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<Box<Hit>>, t_min: f32, t_max: f32) -> BVHNode {
|
||||
eprintln!("l.len() {}", l.len());
|
||||
let mut l: Vec<Box<Hit>> = 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<BVHNode>;
|
||||
let right: Box<BVHNode>;
|
||||
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<Box<Hit>>, t_min: f32, t_max: f32) -> BVHNode {
|
||||
if l.len() == 1 {
|
||||
return BVHNode::Leaf(vec_first_into(l));
|
||||
} else {
|
||||
let mut l: Vec<Box<Hit>> = 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<HitRecord> {
|
||||
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!(
|
||||
|
||||
@ -25,6 +25,8 @@ impl Cube {
|
||||
|
||||
impl Hit for Cube {
|
||||
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
|
||||
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);
|
||||
|
||||
188
rtiow/src/kdtree.rs
Normal file
188
rtiow/src/kdtree.rs
Normal file
@ -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<Hit>),
|
||||
Branch {
|
||||
left: Box<KDTree>,
|
||||
right: Box<KDTree>,
|
||||
bbox: Option<AABB>,
|
||||
},
|
||||
}
|
||||
|
||||
// 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<T>(v: Vec<T>) -> 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<T>(v: Vec<T>, offset: usize) -> (Vec<T>, Vec<T>) {
|
||||
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<Box<Hit>>, 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<HitRecord> {
|
||||
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<AABB> {
|
||||
match self {
|
||||
KDTree::Leaf(ref hit) => hit.bounding_box(t_min, t_max),
|
||||
KDTree::Branch { bbox, .. } => bbox.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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")]
|
||||
|
||||
@ -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<Box<Hit>> = Vec::new();
|
||||
let len = 30;
|
||||
let len = 100;
|
||||
for x in 0..len {
|
||||
for z in 0..len {
|
||||
let r = rng.gen_range::<f32>(0., 1.);
|
||||
@ -45,12 +45,12 @@ pub fn new(opt: &Opt) -> Scene {
|
||||
)));
|
||||
}
|
||||
}
|
||||
let use_bvh = false;
|
||||
let use_kdtree = true;
|
||||
let world: Box<Hit>;
|
||||
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));
|
||||
}
|
||||
|
||||
@ -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<Hit>;
|
||||
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<Hit> = 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<Box<Hit>> {
|
||||
fn random_scene(background_color: Vec3) -> Vec<Box<Hit>> {
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut objects: Vec<Box<Hit>> = 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::<f32>(0., 1.);
|
||||
|
||||
|
||||
@ -2,4 +2,5 @@ pub mod bench;
|
||||
pub mod book;
|
||||
pub mod bvh;
|
||||
pub mod cube;
|
||||
pub mod test;
|
||||
pub mod tutorial;
|
||||
|
||||
80
rtiow/src/scenes/test.rs
Normal file
80
rtiow/src/scenes/test.rs
Normal file
@ -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<Box<Hit>> = 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::<f32>(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<Hit> = 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,
|
||||
}
|
||||
}
|
||||
@ -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<Hit> = 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<Box<Hit>> = vec![
|
||||
//let world: Box<Hit> = 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<Hit> = if opt.use_accel {
|
||||
Box::new(KDTree::new(objects, time_min, time_max))
|
||||
} else {
|
||||
Box::new(HitableList::new(objects))
|
||||
};
|
||||
Scene {
|
||||
camera,
|
||||
world,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user