From fbeadfce29a25807e09b56ff195e05dca630a66c Mon Sep 17 00:00:00 2001 From: Nathan Vegdahl Date: Sun, 14 Aug 2016 00:51:21 -0700 Subject: [PATCH] Use quick select for balanced BVH building. This gets rid of a crate dependency, and also is faster. --- Cargo.lock | 56 +++++++++++++++++++------------------- Cargo.toml | 3 +-- src/algorithm.rs | 70 +++++++++++++++++++++++++++++++++++++++++++++++- src/bvh.rs | 18 ++++++++----- src/main.rs | 1 - 5 files changed, 109 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a78385d..9d8a78b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index 022386f..6202de4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 } \ No newline at end of file +simd = { version = "0.1.1", optional = true } diff --git a/src/algorithm.rs b/src/algorithm.rs index 2b6a0ad..5208691 100644 --- a/src/algorithm.rs +++ b/src/algorithm.rs @@ -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(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(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(slice1: &[T], slice2: &[T], @@ -174,3 +203,42 @@ pub fn merge_slices_to(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); + } +} diff --git a/src/bvh.rs b/src/bvh.rs index bb3538b..a3b5b97 100644 --- a/src/bvh.rs +++ b/src/bvh.rs @@ -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 diff --git a/src/main.rs b/src/main.rs index 4af43c8..555ee18 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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")]