obvhs/cwbvh/
builder.rs

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