obvhs/bvh2/
builder.rs

1use std::time::{Duration, Instant};
2
3use crate::{
4    Boundable, BvhBuildParams, ploc::PlocBuilder, splits::split_aabbs_preset, triangle::Triangle,
5};
6
7use super::{Bvh2, leaf_collapser::collapse, reinsertion::ReinsertionOptimizer};
8
9/// Build a bvh2 from the given list of Triangles.
10/// Just a helper function / example, feel free to reimplement for your specific use case.
11///
12/// # Arguments
13/// * `triangles` - A list of Triangles.
14/// * `config` - Parameters for configuring the BVH building.
15/// * `core_build_time` - The core BVH build time. Does not include things like initial AABB
16///   generation or debug validation. This is mostly just here to simplify profiling in [tray_racing](https://github.com/DGriffin91/tray_racing)
17pub fn build_bvh2_from_tris(
18    triangles: &[Triangle],
19    config: BvhBuildParams,
20    core_build_time: &mut Duration,
21) -> Bvh2 {
22    let mut bvh2;
23    let start_time;
24    if config.pre_split {
25        let mut largest_half_area = 0.0;
26        let mut avg_area = 0.0;
27
28        let mut aabbs = triangles
29            .iter()
30            .map(|tri| {
31                let aabb = tri.aabb();
32                let half_area = aabb.half_area();
33                largest_half_area = half_area.max(largest_half_area);
34                avg_area += half_area;
35                aabb
36            })
37            .collect::<Vec<_>>();
38        let mut indices = (0..triangles.len() as u32).collect::<Vec<_>>();
39
40        avg_area /= triangles.len() as f32;
41
42        start_time = Instant::now();
43
44        split_aabbs_preset(
45            &mut aabbs,
46            &mut indices,
47            triangles,
48            avg_area,
49            largest_half_area,
50        );
51        bvh2 = PlocBuilder::with_capacity(aabbs.len()).build(
52            config.ploc_search_distance,
53            &aabbs,
54            indices,
55            config.sort_precision,
56            config.search_depth_threshold,
57        );
58    } else {
59        start_time = Instant::now();
60        bvh2 = PlocBuilder::with_capacity(triangles.len()).build(
61            config.ploc_search_distance,
62            triangles,
63            (0..triangles.len() as u32).collect::<Vec<_>>(),
64            config.sort_precision,
65            config.search_depth_threshold,
66        );
67    }
68
69    bvh2.uses_spatial_splits = config.pre_split;
70    let mut reinsertion_optimizer = ReinsertionOptimizer::default();
71    reinsertion_optimizer.run(&mut bvh2, config.reinsertion_batch_ratio, None);
72    collapse(
73        &mut bvh2,
74        config.max_prims_per_leaf.clamp(1, 255),
75        config.collapse_traversal_cost,
76    );
77    reinsertion_optimizer.run(
78        &mut bvh2,
79        config.reinsertion_batch_ratio * config.post_collapse_reinsertion_batch_ratio_multiplier,
80        None,
81    );
82
83    *core_build_time += start_time.elapsed();
84
85    #[cfg(debug_assertions)]
86    {
87        bvh2.validate(triangles, false, config.pre_split);
88    }
89
90    bvh2
91}
92
93/// Build a bvh2 from the given list of Boundable primitives.
94/// `pre_split` in BvhBuildParams is ignored in this case.
95/// Just a helper function / example, feel free to reimplement for your specific use case.
96///
97/// # Arguments
98/// * `primitives` - A list of Primitives that implement Boundable.
99/// * `config` - Parameters for configuring the BVH building.
100/// * `core_build_time` - The core BVH build time. Does not include things like initial AABB
101///   generation or debug validation. This is mostly just here to simplify profiling in [tray_racing](https://github.com/DGriffin91/tray_racing)
102// TODO: we could optionally do imprecise basic Aabb splits.
103pub fn build_bvh2<T: Boundable>(
104    primitives: &[T],
105    config: BvhBuildParams,
106    core_build_time: &mut Duration,
107) -> Bvh2 {
108    let start_time = Instant::now();
109
110    let mut bvh2 = PlocBuilder::with_capacity(primitives.len()).build(
111        config.ploc_search_distance,
112        primitives,
113        (0..primitives.len() as u32).collect::<Vec<_>>(),
114        config.sort_precision,
115        config.search_depth_threshold,
116    );
117    let mut reinsertion_optimizer = ReinsertionOptimizer::default();
118    reinsertion_optimizer.run(&mut bvh2, config.reinsertion_batch_ratio, None);
119    collapse(
120        &mut bvh2,
121        config.max_prims_per_leaf.clamp(1, 255),
122        config.collapse_traversal_cost,
123    );
124    reinsertion_optimizer.run(
125        &mut bvh2,
126        config.reinsertion_batch_ratio * config.post_collapse_reinsertion_batch_ratio_multiplier,
127        None,
128    );
129
130    *core_build_time += start_time.elapsed();
131
132    #[cfg(debug_assertions)]
133    {
134        bvh2.validate(primitives, false, config.pre_split);
135    }
136
137    bvh2
138}