cgv
Loading...
Searching...
No Matches
bvh.cxx
1#include "bvh.h"
2
3#include <numeric>
4#include <stack>
5
6#include <cgv/math/intersection.h>
7
8namespace cgv {
9namespace data {
10
11void bvh::build(const std::vector<const ray_intersectable*>& primitives, size_t max_depth) {
12 _max_depth = max_depth;
13
14 // Store the pointers to the given primitives and calculate the bounding box of all primitives.
15 this->_primitives = primitives;
16 cgv::box3 bounds;
17 for(const ray_intersectable* primitive : primitives)
18 bounds.add_axis_aligned_box(primitive->get_bounds());
19
20 // Create the root node containing all primitves and no children.
21 _root->bounds = bounds;
22 _root->primitive_indices.resize(_primitives.size());
23 std::iota(_root->primitive_indices.begin(), _root->primitive_indices.end(), 0);
24 _root->child_a.reset();
25 _root->child_b.reset();
26
27 // Start recursively building the hierarchy by splitting the root node.
28 split(_root.get());
29}
30
31void bvh::split(bvh_node* node, int depth) {
32 // Stop splitting if the maximum depth is reached
33 if(depth == _max_depth)
34 return;
35
36 // Determine the split axis as the axis with the largest extent
37 const unsigned split_axis = cgv::math::max_index(node->bounds.get_extent());
38 const float split_position = node->bounds.get_center()[split_axis];
39
40 node->child_a = std::make_unique<bvh_node>();
41 node->child_b = std::make_unique<bvh_node>();
42 bvh_node* child_a = node->child_a.get();
43 bvh_node* child_b = node->child_b.get();
44
45 // Loop over all primitives in the current node and partition them into the first and second child node based on their center position.
46 for(const size_t i : node->primitive_indices) {
47 const ray_intersectable* primitive = _primitives[i];
48 cgv::box3 primitive_bounds = primitive->get_bounds();
49 bool in_a = primitive_bounds.get_center()[split_axis] < split_position;
50 bvh_node* child = in_a ? child_a : child_b;
51 child->primitive_indices.push_back(i);
52 child->bounds.add_axis_aligned_box(primitive_bounds);
53 }
54
55 // Clear the primitives from the node to reduce memory consumption
56 node->primitive_indices.clear();
57 // Recursively split the two child nodes
58 split(child_a, depth + 1);
59 split(child_b, depth + 1);
60}
61
63 // Keep track of the discovered nodes during depth-first traversal
64 std::stack<bvh_node*> node_stack;
65 node_stack.push(_root.get());
66
67 // Keep track of the closest intersection distance
68 float min_t = std::numeric_limits<float>::max();
69 cgv::vec2 bounds_ts;
70 bvh_result result;
71 ray_intersection_info intersection;
72
73 while(!node_stack.empty()) {
74 const bvh_node* node = node_stack.top();
75 node_stack.pop();
76
77 // First test if the ray hits the current node's bounding box and only proceed if this is the case.
78 if(cgv::math::ray_box_intersection(ray, node->bounds.get_min_pnt(), node->bounds.get_max_pnt(), bounds_ts) > 0) {
79 // A node without child nodes indicates a leaf node possibly containing primitives.
80 if(!node->child_a && !node->child_b) {
81 // Test all primitives inside the current node forintersection with the ray and record the closest inetrsection.
82 for(const size_t i : node->primitive_indices) {
83 const ray_intersectable* primitive = _primitives[i];
84 if(primitive->intersect(ray, intersection)) {
85 if(intersection.t > std::numeric_limits<float>::epsilon() && intersection.t < min_t) {
86 min_t = intersection.t;
87 result.intersection = intersection;
88 result.primitive = primitive;
89 result.primitive_index = i;
90 }
91 }
92 }
93 } else {
94 // If this is not a leaf node push its two child nodes onto the stack to proceeed traversing the hierarchy.
95 node_stack.push(node->child_a.get());
96 node_stack.push(node->child_b.get());
97 }
98 }
99 }
100
101 // A primitive was hit if the resulting intersection has a valid distance.
102 if(result.intersection.t < std::numeric_limits<float>::max())
103 result.is_hit = true;
104
105 return result;
106}
107
108} // namespace data
109} // namespace cgv
void build(const std::vector< const ray_intersectable * > &primitives, size_t max_depth=8)
Build the hierarchy over the given primitives.
Definition bvh.cxx:11
bvh_result closest_intersection(const cgv::ray3 &ray) const
Calculate the closest intersection with positive distance, if any, of the given ray with the stored p...
Definition bvh.cxx:62
An interface to define objects that are intersectable with a ray.
Definition bvh.h:27
virtual bool intersect(const cgv::ray3 &ray, ray_intersection_info &info) const =0
Test if the object is intersected by the given ray.
virtual cgv::box3 get_bounds() const =0
Return the axis-aligned bounding box of the primitive.
fpnt_type get_center() const
return the center of the box
void add_axis_aligned_box(const axis_aligned_box< T, N > &aab)
extent box to include given axis alinged box
this header is dependency free
Definition print.h:11
A single node of a bounding volume hierarchy.
Definition bvh.h:48
std::vector< size_t > primitive_indices
The list of primitive indices contained in this node. After building the tree, only leaf nodes will h...
Definition bvh.h:52
cgv::box3 bounds
The node's axis aligned bounding box.
Definition bvh.h:50
The result of a BVH intersection test.
Definition bvh.h:61
size_t primitive_index
The index of the hit primitive as given during BVH construction.
Definition bvh.h:67
ray_intersection_info intersection
Intersection information of the hit.
Definition bvh.h:65
bool is_hit
True if a primitive was hit.
Definition bvh.h:63
const ray_intersectable * primitive
A pointer to the hit primitive.
Definition bvh.h:69
Holds information about a single intersection of a ray and primitive.
Definition bvh.h:17
float t
The ray parameter.
Definition bvh.h:19
Struct template for fixed n-dimensional rays with arbitrary data type defined by origin and direction...
Definition fray.h:11