MUDA
Loading...
Searching...
No Matches
bvh_viewer.h
1#pragma once
2#include <muda/viewer/viewer_base.h>
3#include <muda/container/vector.h>
4#include <muda/ext/geo/lbvh/aabb.h>
5#include <muda/ext/geo/lbvh/morton_code.h>
6#include <muda/ext/geo/lbvh/predicator.h>
7
8namespace muda::lbvh
9{
10template <typename Real, typename Object, typename AABBGetter, typename MortonCodeCalculator>
11class BVH;
12
13namespace details
14{
15 struct Node
16 {
17 std::uint32_t parent_idx; // parent node
18 std::uint32_t left_idx; // index of left child node
19 std::uint32_t right_idx; // index of right child node
20 std::uint32_t object_idx; // == 0xFFFFFFFF if internal node.
21 };
22
23 template <typename UInt>
24 MUDA_GENERIC uint2 determine_range(UInt const* node_code, const uint32_t num_leaves, uint32_t idx)
25 {
26 if(idx == 0)
27 {
28 return make_uint2(0, num_leaves - 1);
29 }
30
31 // determine direction of the range
32 const UInt self_code = node_code[idx];
33 const int L_delta = common_upper_bits(self_code, node_code[idx - 1]);
34 const int R_delta = common_upper_bits(self_code, node_code[idx + 1]);
35 const int d = (R_delta > L_delta) ? 1 : -1;
36
37 // Compute upper bound for the length of the range
38
39 const int delta_min = thrust::min(L_delta, R_delta);
40 int l_max = 2;
41 int delta = -1;
42 int i_tmp = idx + d * l_max;
43 if(0 <= i_tmp && i_tmp < num_leaves)
44 {
45 delta = common_upper_bits(self_code, node_code[i_tmp]);
46 }
47 while(delta > delta_min)
48 {
49 l_max <<= 1;
50 i_tmp = idx + d * l_max;
51 delta = -1;
52 if(0 <= i_tmp && i_tmp < num_leaves)
53 {
54 delta = common_upper_bits(self_code, node_code[i_tmp]);
55 }
56 }
57
58 // Find the other end by binary search
59 int l = 0;
60 int t = l_max >> 1;
61 while(t > 0)
62 {
63 i_tmp = idx + (l + t) * d;
64 delta = -1;
65 if(0 <= i_tmp && i_tmp < num_leaves)
66 {
67 delta = common_upper_bits(self_code, node_code[i_tmp]);
68 }
69 if(delta > delta_min)
70 {
71 l += t;
72 }
73 t >>= 1;
74 }
75 uint32_t jdx = idx + l * d;
76 if(d < 0)
77 {
78 thrust::swap(idx, jdx); // make it sure that idx < jdx
79 }
80 return make_uint2(idx, jdx);
81 }
82
83 template <typename UInt>
84 MUDA_GENERIC uint32_t find_split(UInt const* node_code,
85 const uint32_t num_leaves,
86 const uint32_t first,
87 const uint32_t last) noexcept
88 {
89 const UInt first_code = node_code[first];
90 const UInt last_code = node_code[last];
91 if(first_code == last_code)
92 {
93 return (first + last) >> 1;
94 }
95 const int delta_node = common_upper_bits(first_code, last_code);
96
97 // binary search...
98 int split = first;
99 int stride = last - first;
100 do
101 {
102 stride = (stride + 1) >> 1;
103 const int middle = split + stride;
104 if(middle < last)
105 {
106 const int delta = common_upper_bits(first_code, node_code[middle]);
107 if(delta > delta_node)
108 {
109 split = middle;
110 }
111 }
112 } while(stride > 1);
113
114 return split;
115 }
116
117
118 template <bool IsConst, typename Real, typename Object>
120 {
121 MUDA_VIEWER_COMMON_NAME(BVHViewerBase);
122
124 template <typename U>
125 using auto_const_t = typename Base::template auto_const_t<U>;
126
127 template <typename Real_, typename Object_, typename AABBGetter, typename MortonCodeCalculator>
128 friend class BVH;
129
130 public:
131 using real_type = Real;
133 using node_type = details::Node;
134 using index_type = std::uint32_t;
135 using object_type = Object;
136
137
141
143 {
144 MUDA_GENERIC void operator()(uint32_t obj_idx) const noexcept {}
145 };
146
147 MUDA_GENERIC BVHViewerBase(const uint32_t num_nodes,
148 const uint32_t num_objects,
149 auto_const_t<node_type>* nodes,
150 auto_const_t<aabb_type>* aabbs,
151 auto_const_t<object_type>* objects)
152 : m_num_nodes(num_nodes)
153 , m_num_objects(num_objects)
154 , m_nodes(nodes)
155 , m_aabbs(aabbs)
156 , m_objects(objects)
157 {
158 MUDA_KERNEL_ASSERT(m_nodes && m_aabbs && m_objects,
159 "BVHViewerBase[%s:%s]: nullptr is passed,"
160 "nodes=%p,"
161 "aabbs=%p,"
162 "objects=%p\n",
163 this->name(),
164 this->kernel_name(),
165 m_nodes,
166 m_aabbs,
167 m_objects);
168 }
169
170 MUDA_GENERIC auto as_const() const noexcept
171 {
172 return ConstViewer{m_num_nodes, m_num_objects, m_nodes, m_aabbs, m_objects};
173 }
174
175 MUDA_GENERIC operator ConstViewer() const noexcept
176 {
177 return as_const();
178 }
179
180 MUDA_GENERIC auto num_nodes() const noexcept { return m_num_nodes; }
181 MUDA_GENERIC auto num_objects() const noexcept { return m_num_objects; }
182
183 // query object indices that potentially overlaps with query aabb.
184 //
185 // requirements:
186 // - F: void (uin32_t obj_idx)
187 template <typename F, uint32_t StackNum = 64>
188 MUDA_GENERIC uint32_t query(const query_overlap<real_type>& q,
189 F callback = DefaultQueryCallback{}) const noexcept
190 {
191 index_type stack[StackNum];
192 index_type* stack_ptr = stack;
193 index_type* stack_end = stack + StackNum;
194 *stack_ptr++ = 0; // root node is always 0
195
196 uint32_t num_found = 0;
197 do
198 {
199 const index_type node = *--stack_ptr;
200 const index_type L_idx = m_nodes[node].left_idx;
201 const index_type R_idx = m_nodes[node].right_idx;
202
203 if(intersects(q.target, m_aabbs[L_idx]))
204 {
205 const auto obj_idx = m_nodes[L_idx].object_idx;
206 if(obj_idx != 0xFFFFFFFF)
207 {
208 if constexpr(!std::is_same_v<F, DefaultQueryCallback>)
209 {
210 callback(obj_idx);
211 }
212 ++num_found;
213 }
214 else // the node is not a leaf.
215 {
216 *stack_ptr++ = L_idx;
217 }
218 }
219 if(intersects(q.target, m_aabbs[R_idx]))
220 {
221 const auto obj_idx = m_nodes[R_idx].object_idx;
222 if(obj_idx != 0xFFFFFFFF)
223 {
224 if constexpr(!std::is_same_v<F, DefaultQueryCallback>)
225 {
226 callback(obj_idx);
227 }
228 ++num_found;
229 }
230 else // the node is not a leaf.
231 {
232 *stack_ptr++ = R_idx;
233 }
234 }
235 MUDA_KERNEL_ASSERT(stack_ptr < stack_end,
236 "LBVHQuery[%s:%s]: stack overflow, try use a larger StackNum.",
237 this->name(),
238 this->kernel_name());
239 } while(stack < stack_ptr);
240 return num_found;
241 }
242
243 // query object index that is the nearst to the query point.
244 //
245 // requirements:
246 // - FDistanceCalculator must be able to calc distance between a point to an object.
247 // which means FDistanceCalculator: Real (const object_type& lhs, const object_type& rhs)
248 //
249 template <typename FDistanceCalculator, uint32_t StackNum = 64>
250 MUDA_GENERIC thrust::pair<uint32_t, real_type> query(
251 const query_nearest<real_type>& q, FDistanceCalculator calc_dist) const noexcept
252 {
253 // pair of {node_idx, mindist}
254 thrust::pair<index_type, real_type> stack[StackNum];
255 thrust::pair<index_type, real_type>* stack_ptr = stack;
256 thrust::pair<index_type, real_type>* stack_end = stack + StackNum;
257
258 *stack_ptr++ = thrust::make_pair(0, mindist(m_aabbs[0], q.target));
259
260 uint32_t nearest = 0xFFFFFFFF;
261 real_type dist_to_nearest_object = infinity<real_type>();
262 do
263 {
264 const auto node = *--stack_ptr;
265 if(node.second > dist_to_nearest_object)
266 {
267 // if aabb mindist > already_found_mindist, it cannot have a nearest
268 continue;
269 }
270
271 const index_type L_idx = m_nodes[node.first].left_idx;
272 const index_type R_idx = m_nodes[node.first].right_idx;
273
274 const aabb_type& L_box = m_aabbs[L_idx];
275 const aabb_type& R_box = m_aabbs[R_idx];
276
277 const real_type L_mindist = mindist(L_box, q.target);
278 const real_type R_mindist = mindist(R_box, q.target);
279
280 const real_type L_minmaxdist = minmaxdist(L_box, q.target);
281 const real_type R_minmaxdist = minmaxdist(R_box, q.target);
282
283 // there should be an object that locates within minmaxdist.
284
285 if(L_mindist <= R_minmaxdist) // L is worth considering
286 {
287 const auto obj_idx = m_nodes[L_idx].object_idx;
288 if(obj_idx != 0xFFFFFFFF) // leaf node
289 {
290 const real_type dist = calc_dist(q.target, m_objects[obj_idx]);
291 if(dist <= dist_to_nearest_object)
292 {
293 dist_to_nearest_object = dist;
294 nearest = obj_idx;
295 }
296 }
297 else
298 {
299 *stack_ptr++ = thrust::make_pair(L_idx, L_mindist);
300 }
301 }
302 if(R_mindist <= L_minmaxdist) // R is worth considering
303 {
304 const auto obj_idx = m_nodes[R_idx].object_idx;
305 if(obj_idx != 0xFFFFFFFF) // leaf node
306 {
307 const real_type dist = calc_dist(q.target, m_objects[obj_idx]);
308 if(dist <= dist_to_nearest_object)
309 {
310 dist_to_nearest_object = dist;
311 nearest = obj_idx;
312 }
313 }
314 else
315 {
316 *stack_ptr++ = thrust::make_pair(R_idx, R_mindist);
317 }
318 }
319 MUDA_KERNEL_ASSERT(stack_ptr < stack_end,
320 "LBVHQuery[%s:%s]: stack overflow, try use a larger StackNum.",
321 this->name(),
322 this->kernel_name());
323 } while(stack < stack_ptr);
324 return thrust::make_pair(nearest, dist_to_nearest_object);
325 }
326
327 MUDA_GENERIC auto_const_t<object_type>& object(const uint32_t idx) noexcept
328 {
329 check_index(idx);
330 return m_objects[idx];
331 }
332
333 MUDA_GENERIC const object_type& object(const uint32_t idx) const noexcept
334 {
335 check_index(idx);
336 return m_objects[idx];
337 }
338
339 private:
340 uint32_t m_num_nodes; // (# of internal node) + (# of leaves), 2N+1
341 uint32_t m_num_objects; // (# of leaves), the same as the number of objects
342
343 auto_const_t<node_type>* m_nodes;
344 auto_const_t<aabb_type>* m_aabbs;
345 auto_const_t<object_type>* m_objects;
346
347 MUDA_INLINE MUDA_GENERIC void check_index(const uint32_t idx) const noexcept
348 {
349 MUDA_KERNEL_ASSERT(idx < m_num_objects,
350 "BVHViewer[%s:%s]: index out of range, idx=%u, num_objects=%u",
351 this->name(),
352 this->kernel_name(),
353 idx,
354 m_num_objects);
355 }
356 };
357} // namespace details
358
359template <typename Real, typename Object>
360using BVHViewer = details::BVHViewerBase<false, Real, Object>;
361template <typename Real, typename Object>
362using CBVHViewer = details::BVHViewerBase<true, Real, Object>;
363} // namespace muda::lbvh
364
365namespace muda
366{
367template <typename Real, typename Object>
368struct read_only_viewer<lbvh::BVHViewer<Real, Object>>
369{
371};
372
373template <typename Real, typename Object>
374struct read_write_viewer<lbvh::CBVHViewer<Real, Object>>
375{
377};
378} // namespace muda
Definition viewer_base.h:18
Definition bvh.h:90
Definition bvh_viewer.h:120
Definition aabb.h:11
Definition bvh_viewer.h:16
Definition type_modifier.h:22
Definition type_modifier.h:28