Use quick select for balanced BVH building.

This gets rid of a crate dependency, and also is faster.
This commit is contained in:
Nathan Vegdahl 2016-08-14 00:51:21 -07:00
parent 024ca560af
commit fbeadfce29
5 changed files with 109 additions and 39 deletions

56
Cargo.lock generated
View File

@ -7,7 +7,6 @@ dependencies = [
"lodepng 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"nom 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.0.0 (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)",
"scoped_threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"simd 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -79,11 +78,6 @@ name = "nom"
version = "1.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "num-traits"
version = "0.1.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "num_cpus"
version = "1.0.0"
@ -92,15 +86,6 @@ dependencies = [
"libc 0.2.14 (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.34 (registry+https://github.com/rust-lang/crates.io-index)",
"unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "0.1.73"
@ -170,24 +155,11 @@ dependencies = [
"winapi 0.2.8 (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]]
name = "utf8-ranges"
version = "0.1.3"
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]]
name = "winapi"
version = "0.2.8"
@ -198,3 +170,31 @@ name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2b3fb52b09c1710b961acb35390d514be82e4ac96a9969a8e38565a29b878dc9"
"checksum c_vec 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "aa9e1d9f7d49e289f36f19effbf3d5a5e30163ecf9c7a3c9be94d5374dec5b9a"
"checksum crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "fb974f835e90390c5f9dfac00f05b06dc117299f5ea4e85fbc7bb443af4911cc"
"checksum docopt 0.6.81 (registry+https://github.com/rust-lang/crates.io-index)" = "323b5c50646d8d3f26c826eb62c15659b2bc031831d56bcdb02e0e49c5b73829"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum libc 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "39dfaaa0f4da0f1a06876c5d94329d739ad0150868069cc235f1ddf80a0480e7"
"checksum lodepng 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2949340106c6ddacb872a8bceb940e39e332739873d56c1315917778527f8779"
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
"checksum nom 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b8c256fd9471521bcb84c3cdba98921497f1a331cbc15b8030fc63b82050ce"
"checksum num-traits 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "95e58eac34596aac30ab134c8a8da9aa2dc99caa4b4b4838e6fc6e298016278f"
"checksum num_cpus 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a859041cbf7a70ea1ece4b87d1a2c6ef364dcb68749c88db1f97304b9ec09d5f"
"checksum quickersort 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5950b7cb98904f6f7856bdff5b0987821f8a4ec4a67f4be892ddc8ed244ce89d"
"checksum regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)" = "56b7ee9f764ecf412c6e2fff779bca4b22980517ae335a21aeaf4e32625a5df2"
"checksum regex-syntax 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "31040aad7470ad9d8c46302dcffba337bb4289ca5da2e3cd6e37b64109a85199"
"checksum rgb 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b5b3c2c5af3cafb6dad34a02c7a5b8818f71992663f5a8b1e1d1e27c5e782dd"
"checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b"
"checksum scoped_threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3ef399c8893e8cb7aa9696e895427fab3a6bf265977bb96e126f24ddd2cda85a"
"checksum simd 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "63b5847c2d766ca7ce7227672850955802fabd779ba616aeabead4c2c3877023"
"checksum strsim 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e4d73a2c36a4d095ed1a6df5cbeac159863173447f7a82b3f4757426844ab825"
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
"checksum thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "55dd963dbaeadc08aa7266bf7f91c3154a7805e32bb94b820b769d2ef3b4744d"
"checksum time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "3c7ec6d62a20df54e07ab3b78b9a3932972f4b7981de295563686849eb3989af"
"checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91"
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"

View File

@ -17,7 +17,6 @@ nom = "1.2"
scoped_threadpool = "0.1"
crossbeam = "0.2"
num_cpus = "1.0"
quickersort = "2.0"
lodepng = "0.8"
simd = { version = "0.1.1", optional = true }
simd = { version = "0.1.1", optional = true }

View File

@ -2,7 +2,7 @@
use std;
use std::cmp;
use std::cmp::Ordering;
use lerp::{Lerp, lerp_slice};
/// Partitions a slice in-place with the given unary predicate, returning
@ -113,6 +113,35 @@ pub fn partition_pair<A, B, F>(slc1: &mut [A], slc2: &mut [B], mut pred: F) -> u
}
}
/// Partitions the slice of items to place the nth-ordered item in the nth place,
/// and the items less than it before and the items more than it after.
pub fn quick_select<T, F>(slc: &mut [T], n: usize, mut order: F)
where F: FnMut(&T, &T) -> Ordering
{
let mut left = 0;
let mut right = slc.len();
loop {
let i = (left + right) / 2;
slc.swap(i, right - 1);
let ii = left +
{
let (val, list) = (&mut slc[left..right]).split_last_mut().unwrap();
partition(list, |n| order(n, val) == Ordering::Less)
};
slc.swap(ii, right - 1);
if ii == n {
return;
} else if ii > n {
right = ii;
} else {
left = ii + 1;
}
}
}
/// Merges two slices of things, appending the result to vec_out
pub fn merge_slices_append<T: Lerp + Copy, F>(slice1: &[T],
slice2: &[T],
@ -174,3 +203,42 @@ pub fn merge_slices_to<T: Lerp + Copy, F>(slice1: &[T],
}
}
}
#[cfg(test)]
mod tests {
use std::cmp::Ordering;
use super::*;
fn quick_select_ints(list: &mut [i32], i: usize) {
quick_select(list, i, |a, b| {
if a < b {
Ordering::Less
} else if a == b {
Ordering::Equal
} else {
Ordering::Greater
}
});
}
#[test]
fn quick_select_1() {
let mut list = [8, 9, 7, 4, 6, 1, 0, 5, 3, 2];
quick_select_ints(&mut list, 5);
assert_eq!(list[5], 5);
}
#[test]
fn quick_select_2() {
let mut list = [8, 9, 7, 4, 6, 1, 0, 5, 3, 2];
quick_select_ints(&mut list, 3);
assert_eq!(list[3], 3);
}
#[test]
fn quick_select_3() {
let mut list = [8, 9, 7, 4, 6, 1, 0, 5, 3, 2];
quick_select_ints(&mut list, 0);
assert_eq!(list[0], 0);
}
}

View File

@ -2,12 +2,11 @@
use std;
use std::cmp::Ordering;
use quickersort::sort_by;
use lerp::lerp_slice;
use bbox::BBox;
use boundable::Boundable;
use ray::AccelRay;
use algorithm::{partition, merge_slices_append};
use algorithm::{partition, quick_select, merge_slices_append};
use math::log2_64;
use sah::sah_split;
@ -156,10 +155,15 @@ impl BVH {
axis
};
// TODO: use a select algorithm like introselect instead of a
// full sort.
sort_by(objects,
&|a, b| {
let place = {
let place = objects.len() / 2;
if place > 0 {
place
} else {
1
}
};
quick_select(objects, place, |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.get_n(split_axis) + tb_a.max.get_n(split_axis)) *
@ -176,7 +180,7 @@ impl BVH {
}
});
(objects.len() / 2, split_axis)
(place, split_axis)
};
// Create child nodes

View File

@ -4,7 +4,6 @@ extern crate docopt;
extern crate scoped_threadpool;
extern crate crossbeam;
extern crate num_cpus;
extern crate quickersort;
extern crate lodepng;
#[cfg(feature = "simd_perf")]