avian3d/collider_tree/
traverse.rs1#![allow(clippy::unnecessary_cast)]
2
3use obvhs::{aabb::Aabb, bvh2::node::Bvh2Node, fast_stack};
4
5use crate::{
6 collider_tree::{
7 Bvh2Ext, ColliderTree, ProxyId,
8 obvhs_ext::{Sweep, SweepHit},
9 obvhs_ray,
10 },
11 math::{AsF32, Dir, Ray, Scalar, Vector},
12};
13
14impl ColliderTree {
15 #[inline(always)]
24 pub fn ray_traverse_closest<F: FnMut(ProxyId) -> Scalar>(
25 &self,
26 ray: Ray,
27 max_distance: Scalar,
28 mut intersection_fn: F,
29 ) -> Option<(ProxyId, Scalar)> {
30 let obvhs_ray = obvhs_ray(&ray, max_distance as f32);
31 let mut hit = obvhs::ray::RayHit::none();
32
33 let found_hit = self
34 .bvh
35 .ray_traverse(obvhs_ray, &mut hit, |_ray, primitive_id| {
36 let proxy_id = ProxyId::new(self.bvh.primitive_indices[primitive_id]);
37 intersection_fn(proxy_id) as f32
38 });
39
40 if found_hit {
41 let proxy_id = ProxyId::new(self.bvh.primitive_indices[hit.primitive_id as usize]);
42 Some((proxy_id, hit.t as Scalar))
43 } else {
44 None
45 }
46 }
47
48 #[inline(always)]
59 pub fn ray_traverse_all<F: FnMut(ProxyId) -> bool>(
60 &self,
61 ray: Ray,
62 max_distance: Scalar,
63 mut intersection_fn: F,
64 ) {
65 let obvhs_ray = obvhs_ray(&ray, max_distance as f32);
66
67 self.bvh
68 .ray_traverse_anyhit(obvhs_ray, |_ray, primitive_id| {
69 let proxy_id = ProxyId::new(self.bvh.primitive_indices[primitive_id]);
70 intersection_fn(proxy_id);
71 });
72 }
73
74 #[inline(always)]
85 pub fn sweep_traverse_closest<F: FnMut(ProxyId) -> Scalar>(
86 &self,
87 aabb: Aabb,
88 direction: Dir,
89 max_distance: Scalar,
90 target_distance: Scalar,
91 mut intersection_fn: F,
92 ) -> Option<(ProxyId, Scalar)> {
93 #[cfg(feature = "2d")]
94 let direction = direction.extend(0.0).to_array().into();
95 #[cfg(feature = "3d")]
96 let direction = direction.to_array().into();
97 let sweep = Sweep::new(aabb, direction, target_distance as f32, max_distance as f32);
98
99 let mut hit = SweepHit::none();
100
101 let found_hit = self
102 .bvh
103 .sweep_traverse(sweep, &mut hit, |_sweep, primitive_id| {
104 let proxy_id = ProxyId::new(self.bvh.primitive_indices[primitive_id]);
105 intersection_fn(proxy_id) as f32
106 });
107
108 if found_hit {
109 let proxy_id = ProxyId::new(self.bvh.primitive_indices[hit.primitive_id as usize]);
110 Some((proxy_id, hit.t as Scalar))
111 } else {
112 None
113 }
114 }
115
116 #[inline(always)]
127 pub fn sweep_traverse_all<F: FnMut(ProxyId) -> bool>(
128 &self,
129 aabb: Aabb,
130 direction: Dir,
131 target_distance: Scalar,
132 max_distance: Scalar,
133 mut intersection_fn: F,
134 ) {
135 #[cfg(feature = "2d")]
136 let direction = direction.extend(0.0).to_array().into();
137 #[cfg(feature = "3d")]
138 let direction = direction.to_array().into();
139 let sweep = Sweep::new(aabb, direction, target_distance as f32, max_distance as f32);
140
141 let mut intersect_prims = |node: &Bvh2Node, _sweep: &mut Sweep, _hit: &mut SweepHit| {
142 for primitive_id in node.first_index..node.first_index + node.prim_count {
143 let proxy_id = ProxyId::new(self.bvh.primitive_indices[primitive_id as usize]);
144 intersection_fn(proxy_id);
145 }
146 true
147 };
148
149 let mut hit = SweepHit::none();
150 fast_stack!(u32, (96, 192), self.bvh.max_depth, stack, {
151 self.bvh
152 .sweep_traverse_dynamic(&mut stack, sweep, &mut hit, &mut intersect_prims)
153 });
154 }
155
156 #[inline(always)]
164 pub fn squared_distance_traverse_closest<F: FnMut(ProxyId) -> Scalar>(
165 &self,
166 point: Vector,
167 max_distance_squared: Scalar,
168 mut eval: F,
169 ) -> Option<(ProxyId, Scalar)> {
170 #[cfg(feature = "2d")]
171 let point = point.f32().extend(0.0).to_array().into();
172 #[cfg(feature = "3d")]
173 let point = point.f32().to_array().into();
174
175 let closest_leaf = self.bvh.squared_distance_traverse(
176 point,
177 max_distance_squared as f32,
178 |_point, primitive_id| {
179 let proxy_id = ProxyId::new(self.bvh.primitive_indices[primitive_id]);
180 eval(proxy_id) as f32
181 },
182 );
183
184 if let Some((primitive_id, distance_squared)) = closest_leaf {
185 let proxy_id = ProxyId::new(self.bvh.primitive_indices[primitive_id as usize]);
186 Some((proxy_id, distance_squared as Scalar))
187 } else {
188 None
189 }
190 }
191
192 #[inline(always)]
200 pub fn point_traverse<F: FnMut(ProxyId) -> bool>(&self, point: Vector, mut eval: F) {
201 #[cfg(feature = "2d")]
202 let point = point.f32().extend(0.0).to_array().into();
203 #[cfg(feature = "3d")]
204 let point = point.f32().to_array().into();
205
206 self.bvh.point_traverse(point, |bvh, node_index| {
207 let node = &bvh.nodes[node_index as usize];
208 let start = node.first_index as usize;
209 let end = start + node.prim_count as usize;
210
211 for primitive_id in start..end {
212 let proxy_id = ProxyId::new(bvh.primitive_indices[primitive_id]);
213 if !eval(proxy_id) {
214 return false;
215 }
216 }
217
218 true
219 });
220 }
221
222 #[inline(always)]
230 pub fn aabb_traverse<F: FnMut(ProxyId) -> bool>(&self, aabb: Aabb, mut eval: F) {
231 self.bvh.aabb_traverse(aabb, |bvh, node_index| {
232 let node = &bvh.nodes[node_index as usize];
233 let start = node.first_index as usize;
234 let end = start + node.prim_count as usize;
235
236 for primitive_id in start..end {
237 let proxy_id = ProxyId::new(bvh.primitive_indices[primitive_id]);
238 if !eval(proxy_id) {
239 return false;
240 }
241 }
242
243 true
244 });
245 }
246}