Special case BVH building when we get too close to max depth.

This avoids exceeding max BVH depth even in pathological cases.
Still need improve non-worst case building, but this at least
prevents crashes in worst case.
This commit is contained in:
Nathan Vegdahl 2016-07-16 00:05:23 -07:00
parent c372d485e2
commit 35ef58b09c
5 changed files with 82 additions and 5 deletions

28
Cargo.lock generated
View File

@ -7,6 +7,7 @@ dependencies = [
"lodepng 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "lodepng 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"nom 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "nom 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
"quickersort 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"scoped_threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "scoped_threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -76,6 +77,11 @@ name = "nom"
version = "1.2.3" version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "num-traits"
version = "0.1.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "num_cpus" name = "num_cpus"
version = "0.2.12" version = "0.2.12"
@ -84,6 +90,15 @@ dependencies = [
"libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "quickersort"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)",
"unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "regex" name = "regex"
version = "0.1.71" version = "0.1.71"
@ -138,11 +153,24 @@ dependencies = [
"thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "unreachable"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "utf8-ranges" name = "utf8-ranges"
version = "0.1.3" version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.2.7" version = "0.2.7"

View File

@ -10,4 +10,5 @@ nom = "1.2"
scoped_threadpool = "0.1" scoped_threadpool = "0.1"
crossbeam = "0.2" crossbeam = "0.2"
num_cpus = "0.2" num_cpus = "0.2"
quickersort = "2.0"
lodepng = "0.8" lodepng = "0.8"

View File

@ -1,10 +1,15 @@
#![allow(dead_code)] #![allow(dead_code)]
use std::cmp::Ordering;
use quickersort::sort_by;
use lerp::lerp_slice; use lerp::lerp_slice;
use bbox::BBox; use bbox::BBox;
use boundable::Boundable; use boundable::Boundable;
use ray::AccelRay; use ray::AccelRay;
use algorithm::{partition, merge_slices_append}; use algorithm::{partition, merge_slices_append};
use math::log2_64;
const BVH_MAX_DEPTH: usize = 64;
#[derive(Debug)] #[derive(Debug)]
pub struct BVH { pub struct BVH {
@ -129,10 +134,15 @@ impl BVH {
2 2
} }
}; };
let split_pos = (bounds.min[split_axis] + bounds.max[split_axis]) * 0.5;
// Partition objects based on split // Partition objects based on split.
let split_index = { // If we're too near the max depth, we do balanced building to
// avoid exceeding max depth.
// Otherwise we do cooler clever stuff to build better trees.
let split_index = if (log2_64(objects.len() as u64) as usize) <
(BVH_MAX_DEPTH - depth) {
// Clever splitting, when we have room to play
let split_pos = (bounds.min[split_axis] + bounds.max[split_axis]) * 0.5;
let mut split_i = partition(&mut objects[..], |obj| { let mut split_i = partition(&mut objects[..], |obj| {
let tb = lerp_slice(bounder(obj), 0.5); let tb = lerp_slice(bounder(obj), 0.5);
let centroid = (tb.min[split_axis] + tb.max[split_axis]) * 0.5; let centroid = (tb.min[split_axis] + tb.max[split_axis]) * 0.5;
@ -143,6 +153,25 @@ impl BVH {
} }
split_i split_i
} else {
// Balanced splitting, when we don't have room to play
sort_by(objects,
&|a, b| {
let tb_a = lerp_slice(bounder(a), 0.5);
let tb_b = lerp_slice(bounder(b), 0.5);
let centroid_a = (tb_a.min[split_axis] + tb_a.max[split_axis]) * 0.5;
let centroid_b = (tb_b.min[split_axis] + tb_b.max[split_axis]) * 0.5;
if centroid_a < centroid_b {
Ordering::Less
} else if centroid_a == centroid_b {
Ordering::Equal
} else {
Ordering::Greater
}
});
objects.len() / 2
}; };
// Create child nodes // Create child nodes
@ -186,8 +215,8 @@ impl BVH {
return; return;
} }
let mut i_stack = [0; 256]; let mut i_stack = [0; BVH_MAX_DEPTH + 1];
let mut ray_i_stack = [rays.len(); 256]; let mut ray_i_stack = [rays.len(); BVH_MAX_DEPTH + 1];
let mut stack_ptr = 1; let mut stack_ptr = 1;
while stack_ptr > 0 { while stack_ptr > 0 {

View File

@ -3,6 +3,7 @@ extern crate docopt;
extern crate scoped_threadpool; extern crate scoped_threadpool;
extern crate crossbeam; extern crate crossbeam;
extern crate num_cpus; extern crate num_cpus;
extern crate quickersort;
extern crate lodepng; extern crate lodepng;
#[macro_use] #[macro_use]
extern crate nom; extern crate nom;

View File

@ -40,6 +40,24 @@ pub fn fast_ln(x: f32) -> f32 {
pub fn log2_64(value: u64) -> u64 {
const TAB64: [u64; 64] = [63, 0, 58, 1, 59, 47, 53, 2, 60, 39, 48, 27, 54, 33, 42, 3, 61, 51,
37, 40, 49, 18, 28, 20, 55, 30, 34, 11, 43, 14, 22, 4, 62, 57, 46,
52, 38, 26, 32, 41, 50, 36, 17, 19, 29, 10, 13, 21, 56, 45, 25, 31,
35, 16, 9, 12, 44, 24, 15, 8, 23, 7, 6, 5];
let value = value | (value >> 1);
let value = value | (value >> 2);
let value = value | (value >> 4);
let value = value | (value >> 8);
let value = value | (value >> 16);
let value = value | (value >> 32);
TAB64[((((value - (value >> 1)) * 0x07EDD5E59A4E28C2)) >> 58) as usize]
}
/// Creates a coordinate system from a single vector. /// Creates a coordinate system from a single vector.
pub fn coordinate_system_from_vector(v: Vector) -> (Vector, Vector, Vector) { pub fn coordinate_system_from_vector(v: Vector) -> (Vector, Vector, Vector) {
let v2 = if v[0].abs() > v[1].abs() { let v2 = if v[0].abs() > v[1].abs() {