From 3afe51c4c71f83600707d54cc22ea12f863a3c8c Mon Sep 17 00:00:00 2001 From: STP Date: Wed, 29 Nov 2023 20:46:35 -0500 Subject: [PATCH] bvh! --- src/bvh.rs | 270 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 251 insertions(+), 19 deletions(-) diff --git a/src/bvh.rs b/src/bvh.rs index d983ff6..e7ee27e 100644 --- a/src/bvh.rs +++ b/src/bvh.rs @@ -1,11 +1,14 @@ -use crate::{ray::*, EPSILON}; -use nalgebra::{Point3, Vector3}; +use crate::{node::Node, ray::*, EPSILON}; +use nalgebra::{point, Point3, Vector3}; +use std::collections::HashMap; +use std::ops::Index; // BOUNDING BOX ----------------------------------------------------------------- #[derive(Clone)] pub struct AABB { pub bln: Point3, pub trf: Point3, + pub centroid: Point3, } impl AABB { @@ -13,7 +16,15 @@ impl AABB { pub fn new(bln: Point3, trf: Point3) -> AABB { let bln = bln + Vector3::new(EPSILON, EPSILON, EPSILON); let trf = trf - Vector3::new(EPSILON, EPSILON, EPSILON); - AABB { bln, trf } + let centroid = bln + (bln - trf) / 2.0; + AABB { bln, trf, centroid } + } + pub fn empty() -> AABB { + AABB { + bln: Point3::new(0.0, 0.0, 0.0), + trf: Point3::new(0.0, 0.0, 0.0), + centroid: Point3::new(0.0, 0.0, 0.0), + } } // Intersect bounding box exactly pub fn intersect_bounding_box(&self, ray: &Ray) -> bool { @@ -69,7 +80,7 @@ impl AABB { } // Get the center of this bounding box fn get_centroid(&self) -> Point3 { - self.bln + (self.trf - self.bln) / 2.0 + self.centroid } // Make a new AABB that contains both pub fn join(&self, other: &AABB) -> AABB { @@ -86,6 +97,19 @@ impl AABB { ), ) } + //Join mutably + pub fn join_mut(&mut self, other: &AABB) { + self.bln = Point3::new( + self.bln.x.min(other.bln.x), + self.bln.y.min(other.bln.y), + self.bln.z.min(other.bln.z), + ); + self.trf = Point3::new( + self.trf.x.max(other.trf.x), + self.trf.y.max(other.trf.y), + self.trf.z.max(other.trf.z), + ); + } //Grow the AABB to contain the cover the point pub fn grow(&self, other: &Point3) -> AABB { AABB::new( @@ -101,11 +125,23 @@ impl AABB { ), ) } + //Grow mutably + pub fn grow_mut(&mut self, other: &Point3) { + self.bln = Point3::new( + self.bln.x.min(other.x), + self.bln.y.min(other.y), + self.bln.z.min(other.z), + ); + self.trf = Point3::new( + self.trf.x.max(other.x), + self.trf.y.max(other.y), + self.trf.z.max(other.z), + ); + } // Size of AABB pub fn size(&self) -> Vector3 { self.trf - self.bln - } - //Surface area of AABB + } //Surface area of AABB pub fn surface_area(&self) -> f64 { let size = self.size(); 2.0 * (size.x * size.y + size.x * size.z + size.y * size.z) @@ -117,18 +153,214 @@ impl AABB { } } -pub enum BVHNode<'a> { - Leaf { - parent: &'a BVHNode<'a>, - bounding_box: AABB, - depth: u32, - }, - Node { - parent: Option<&'a BVHNode<'a>>, - child_l: &'a BVHNode<'a>, - child_r: &'a BVHNode<'a>, - depth: u32, - }, +// Index implemntation of the BVH tree +// pub enum BVHNode { +// Leaf { +// p_idx: usize, //Parent index +// depth: usize, //Depth in BVH tree +// n_idx: usize, //Node index in corrosponding Vec +// }, +// Node { +// p_idx: usize, //Parent index +// l_idx: usize, //Left child index +// l_aabb: AABB, //Left AABB +// r_idx: usize, //Right child index +// r_aabb: AABB, //Right AABB +// depth: usize, //Depth in BVH tree +// }, +// } +// impl BVHNode { +// //Get parent +// fn get_parent(&self) -> usize { +// match *self { +// BVHNode::Node { p_idx, .. } | BVHNode::Leaf { p_idx, .. } => p_idx, +// } +// } +// //Get the left child of a node +// fn get_child_l(&self) -> usize { +// match *self { +// BVHNode::Leaf { .. } => panic!("Cannot get child of leaf node"), +// BVHNode::Node { l_idx, .. } => l_idx, +// } +// } +// // Get right child +// fn get_child_r(&self) -> usize { +// match *self { +// BVHNode::Leaf { .. } => panic!("Cannot get child of leaf node"), +// BVHNode::Node { r_idx, .. } => r_idx, +// } +// } +// // Get the depth of selected node +// pub fn depth(&self) -> usize { +// match *self { +// BVHNode::Node { depth, .. } | BVHNode::Leaf { depth, .. } => depth, +// } +// } +// // Get the aabb of the current node, if leaf return the primitives aabb +// // If node return the join of the two child nodes +// pub fn get_node_aabb(&self, nodes: &Vec) -> AABB { +// match *self { +// BVHNode::Node { l_aabb, r_aabb, .. } => l_aabb.join(&r_aabb), +// BVHNode::Leaf { aabb, .. } => aabb, +// } +// } +// } +// //Implementation of the BVH +// pub struct BVHTree<'a> { +// pub nodes: &'a HashMap, +// pub bvh_nodes: Vec, +// } + +// impl<'a> BVHTree<'a> { +// //Generate a BVH tree given a vector of nodes +// pub fn new(nodes: &HashMap) -> BVHTree { +// //We will make an aabb that bounds all shapes +// let mut root_aabb = AABB::empty(); +// let mut root_centroid = AABB::empty(); +// for (_, node) in nodes { +// let node_aabb = node.primitive.get_aabb(); +// root_aabb.join_mut(&node_aabb); +// root_centroid.grow_mut(&node_aabb.get_centroid()); +// } + +// //We will make an aabb that bounds all centroids +// return BVHTree { +// nodes: &HashMap::new(), +// bvh_nodes: vec![], +// }; +// } +// } + +pub struct BVHNode { + aabb: AABB, //The nodes bounding box + l_idx: usize, //Child node l, the right node is alway l_idx + 1 + first_prim: usize, //First primitive that the node encapsulates + prim_count: usize, //Number of primitives the node encapsulates } -impl<'a> BVHNode<'a> {} +pub struct BVH { + bvh_nodes: Vec, //BVH nodes with AABBs + nodes: Vec, //Nodes with primitives + nodes_used: usize, + root_node_index: usize, +} + +impl BVH { + //Build a bvh by subdividing recursively + fn build(in_nodes: HashMap) -> BVH { + //Make our own vec of nodes so that we can refer to it by index + //Might be long to copy scene, so alternative methods may be prefered + let nodes = vec![]; + for (_, node) in in_nodes { + nodes.push(node); + } + + //A BVH tree will be maximum size of 2*n + 1 + let n = nodes.len(); + let mut bvh_nodes: Vec = Vec::with_capacity(2 * n + 1); + + //Begin constructing our BVH tree + let root_node_index = 0; + let nodes_used = 1; + let tree = BVH { + nodes, + bvh_nodes, + root_node_index, + nodes_used, + }; + + // Get the root node and assign it to index 0 + let mut root = &bvh_nodes[root_node_index]; + (root.l_idx, root.r_idx) = (0, 0); //Root node has no children to begin with + (root.first_prim, root.prim_count) = (0, n); //Make root include all n nodes + tree.update_bvh_node_aabb(root_node_index); //Fit the root nodes AABB + tree.subdivide(root_node_index); + tree + } + // Will update the node's AABB at bvh[index] + fn update_bvh_node_aabb(&mut self, index: usize) { + // We will make his node bound all its primitives + let bvh_node = &self.bvh_nodes[index]; //Get the BVHNode we are working + let bvh_node_aabb = AABB::empty(); //Create the BVHNode's AABB + + let start_index = bvh_node.first_prim; //Start index of the first primitive the node contains + let count = bvh_node.prim_count; //Number of primitives within the nodes aabb + + for i in 0..count { + let primitive = &self.nodes[start_index + i].primitive; //Get the primitive from the Vec + let node_aabb = primitive.get_aabb(); //Get the primitives aabb + bvh_node_aabb.join_mut(&node_aabb); //Join it with the bvh_nodes aabb + } + } + + fn subdivide(&mut self, index: usize) { + // Determine the axis and position of the split plane + // Split the group of primitives in two halves using the split plane + // Create child nodes for each half + // Recurse into each of the child nodes. + + // Get information about the node we want to subdivide + let bvh_node = &self.bvh_nodes[index]; //Get the BVHNode we are working + + /* ----------------- SUBDIVIDE BY CENTROID --------------------- */ + // let bvh_node_centroid_aabb = AABB::empty(); //Create the BVHNode's AABB + // let start_index = bvh_node.first_prim; //Start index of the first primitive the node contains + // let count = bvh_node.prim_count; //Number of primitives within the nodes aabb + // for i in 0..count { + // let primitive = &self.nodes[start_index + i].primitive; //Get the primitive from the Vec + // let node_aabb_centroid = primitive.get_aabb().get_centroid(); //Get the primitives aabb centroid + // bvh_node_centroid_aabb.grow_mut(&node_aabb_centroid); // Grow the aabb to include the all centroids + // } + + /* ------------ SUBDIVIDE BY LONGEST AXIS ------------ */ + + let (bln, trf) = (bvh_node.aabb.bln, bvh_node.aabb.trf); + let extent = trf - bln; + let axis = 0; // Assume that x is longest + if extent.y > extent.x { + axis = 1 // Split y if longer + }; + if extent.z > extent[axis] { + axis = 2 // Split z if loner + }; + let split_pos = bln[axis] + extent[axis] * 0.5; //Final split along this axis + + //Perform a quicksort our nodes + let i = bvh_node.first_prim; + let j = i + bvh_node.prim_count - 1; + while i <= j { + let centroid = self.nodes[i].primitive.get_aabb().get_centroid(); + if centroid[axis] < split_pos { + i += 1; //If it is on left split remain in place + } else { + self.nodes.swap(i, j); //Move to right split + j -= 1; + } + } + //Now we have two children, the lhs of the array is in the left split, and the rhs of the array is on the right split + let left_count = i - bvh_node.first_prim; //Number of prims on lhs + if left_count == 0 || left_count == bvh_node.prim_count { + return; //If we have no more on the left, disregard + } + let l_idx = self.nodes_used; //Left child + self.nodes_used += 1; + let r_idx = self.nodes_used; //Right child + self.nodes_used += 1; + + bvh_node.l_idx = l_idx; + + self.bvh_nodes[l_idx].first_prim = bvh_node.first_prim; //Set left split + self.bvh_nodes[l_idx].prim_count = left_count; //We know this info from our quicksort + + self.bvh_nodes[r_idx].first_prim = i; //Set right split information + self.bvh_nodes[r_idx].prim_count = bvh_node.prim_count - left_count; + bvh_node.prim_count = 0; + + self.update_bvh_node_aabb(l_idx); //Update AABB for left of split + self.update_bvh_node_aabb(r_idx); //Update AABB for right of split + + //Recurse + self.subdivide(l_idx); + self.subdivide(r_idx); + } +}