From a4a73713d22f7a185654cbc934ddd6dd3bbad5cc Mon Sep 17 00:00:00 2001 From: Nathan Vegdahl Date: Sat, 1 Jul 2017 12:44:19 -0700 Subject: [PATCH] Created crate for BVH node traversal order calculations. Might move this into the main source base at some point, but I'm not totally sure about the correctness of the table yet, so would like to generate it for now. --- Cargo.lock | 5 ++ Cargo.toml | 4 ++ sub_crates/bvh_order/Cargo.toml | 10 +++ sub_crates/bvh_order/build.rs | 105 ++++++++++++++++++++++++++++++++ sub_crates/bvh_order/src/lib.rs | 34 +++++++++++ 5 files changed, 158 insertions(+) create mode 100644 sub_crates/bvh_order/Cargo.toml create mode 100644 sub_crates/bvh_order/build.rs create mode 100644 sub_crates/bvh_order/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index aa85c37..05972c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,6 +30,10 @@ name = "bitflags" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bvh_order" +version = "0.1.0" + [[package]] name = "byteorder" version = "1.0.0" @@ -158,6 +162,7 @@ name = "psychopath" version = "0.1.0" dependencies = [ "base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bvh_order 0.1.0", "clap 2.24.2 (registry+https://github.com/rust-lang/crates.io-index)", "color 0.1.0", "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 088dc73..9615bf4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [workspace] members = [ + "sub_crates/bvh_order", "sub_crates/color", "sub_crates/float4", "sub_crates/halton", @@ -36,6 +37,9 @@ scoped_threadpool = "0.1" time = "0.1" # Local crate dependencies +[dependencies.bvh_order] +path = "sub_crates/bvh_order" + [dependencies.color] path = "sub_crates/color" diff --git a/sub_crates/bvh_order/Cargo.toml b/sub_crates/bvh_order/Cargo.toml new file mode 100644 index 0000000..623ca09 --- /dev/null +++ b/sub_crates/bvh_order/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "bvh_order" +version = "0.1.0" +authors = ["Nathan Vegdahl "] +license = "MIT" +build = "build.rs" + +[lib] +name = "bvh_order" +path = "src/lib.rs" diff --git a/sub_crates/bvh_order/build.rs b/sub_crates/bvh_order/build.rs new file mode 100644 index 0000000..0f46941 --- /dev/null +++ b/sub_crates/bvh_order/build.rs @@ -0,0 +1,105 @@ +// Generate table for traversal order of quad BVHs. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::Path; + +fn main() { + // Build the traversal table. + let mut traversal_table = [ + Vec::new(), + Vec::new(), + Vec::new(), + Vec::new(), + Vec::new(), + Vec::new(), + Vec::new(), + Vec::new(), + ]; + for raydir in 0..8 { + let ray = [raydir & 1, (raydir >> 1) & 1, (raydir >> 2) & 1]; + + for s2 in 0..3 { + for s1 in 0..3 { + for s0 in 0..3 { + let mut perm = [0, 1, 2, 3]; + if ray[s1] == 1 { + perm.swap(0, 1); + } + if ray[s2] == 1 { + perm.swap(2, 3); + } + if ray[s0] == 1 { + perm.swap(0, 2); + perm.swap(1, 3); + } + traversal_table[raydir].push( + perm[0] + (perm[1] << 2) + (perm[2] << 4) + + (perm[3] << 6), + ); + } + } + } + + for s1 in 0..3 { + for s0 in 0..3 { + let mut perm = [0, 1, 2]; + if ray[s1] == 1 { + perm.swap(0, 1); + } + if ray[s0] == 1 { + perm.swap(0, 1); + perm.swap(0, 2); + } + traversal_table[raydir].push(perm[0] + (perm[1] << 2) + (perm[2] << 4)); + } + } + + for s1 in 0..3 { + for s0 in 0..3 { + let mut perm = [0, 1, 2]; + if ray[s1] == 1 { + perm.swap(1, 2); + } + if ray[s0] == 1 { + perm.swap(0, 2); + perm.swap(0, 1); + } + traversal_table[raydir].push(perm[0] + (perm[1] << 2) + (perm[2] << 4)); + } + } + + for s0 in 0..3 { + let mut perm = [0, 1]; + if ray[s0] == 1 { + perm.swap(0, 1); + } + traversal_table[raydir].push(perm[0] + (perm[1] << 2)); + } + } + + // Write traversal table to Rust file + let out_dir = env::var("OUT_DIR").unwrap(); + let dest_path = Path::new(&out_dir).join("table_inc.rs"); + let mut f = File::create(&dest_path).unwrap(); + + f.write_all("pub static TRAVERSAL_TABLE: [[u8; 48]; 8] = [".as_bytes()) + .unwrap(); + + for sub_table in traversal_table.iter() { + f.write_all("\n [".as_bytes()).unwrap(); + for (i, n) in sub_table.iter().enumerate() { + if i == 27 || i == 36 || i == 45 { + f.write_all("\n ".as_bytes()).unwrap(); + } + f.write_all(format!("{}", n).as_bytes()).unwrap(); + if i != 47 { + f.write_all(", ".as_bytes()).unwrap(); + } + } + f.write_all("],".as_bytes()).unwrap(); + } + + f.write_all("\n];".as_bytes()).unwrap(); +} diff --git a/sub_crates/bvh_order/src/lib.rs b/sub_crates/bvh_order/src/lib.rs new file mode 100644 index 0000000..fc52a5e --- /dev/null +++ b/sub_crates/bvh_order/src/lib.rs @@ -0,0 +1,34 @@ +#![allow(dead_code)] + +// Include the file generated by the build.rs script +include!(concat!(env!("OUT_DIR"), "/table_inc.rs")); + +/// Represents the split axes of the BVH2 node(s) that a BVH4 node was created +/// from. +/// +/// * `Full` means four nodes from three splits: top, left, and right. +/// * `Left` is three nodes from two splits: top and left. +/// * `Right` is three nodes from two splits: top and right. +/// * `TopOnly` is two nodes from one split (in other words, the BVH4 node is +/// identical to the single BVH2 node that it was created from). +/// +/// Left in this case means the node whose coordinate on the top split-axis is +/// lower. For example, if the top split is on the x axis, then `left.x <= right.x`. +#[derive(Debug, Copy, Clone)] +pub enum SplitAxes { + Full((u8, u8, u8)), // top, left, right + Left((u8, u8)), // top, left + Right((u8, u8)), // top, right + TopOnly(u8), // top +} + +/// Calculates the traversal code for a BVH4 node based on the splits and +/// topology of its children. +pub fn calc_traversal_code(split: SplitAxes) -> u8 { + match split { + SplitAxes::Full((top, left, right)) => top + (left * 3) + (right * 9), + SplitAxes::Left((top, left)) => top + (left * 3) + 27, + SplitAxes::Right((top, right)) => top + (right * 3) + (27 + 9), + SplitAxes::TopOnly(top) => top + (27 + 9 + 9), + } +}