1
- #ifndef PBAT_GEOMETRY_BOUNDING_VOLUME_HIERARCHY_H
2
- #define PBAT_GEOMETRY_BOUNDING_VOLUME_HIERARCHY_H
1
+ /* *
2
+ * @file BoundingVolumeHierarchy.h
3
+ * @author Quoc-Minh Ton-That ([email protected] )
4
+ * @brief Bounding volume hierarchy (BVH) implementation for spatial partitioning of primitives.
5
+ * @date 2025-02-12
6
+ *
7
+ * @copyright Copyright (c) 2025
8
+ *
9
+ */
10
+
11
+ #ifndef PBAT_GEOMETRY_BOUNDINGVOLUMEHIERARCHY_H
12
+ #define PBAT_GEOMETRY_BOUNDINGVOLUMEHIERARCHY_H
3
13
4
14
#include " KdTree.h"
5
15
@@ -18,44 +28,52 @@ namespace geometry {
18
28
* @brief CRTP base class for BVHs.
19
29
*
20
30
* @tparam TDerived Type of the child class (the concrete BVH implementation)
21
- * @tparam TPrimitive Type of primitives stored in the BVH
22
31
* @tparam TBoundingVolume Type of bounding volumes used in the BVH tree
32
+ * @tparam TPrimitive Type of primitives stored in the BVH
23
33
* @tparam Dims Embedding dimensionality
24
34
*/
25
35
template <class TDerived , class TBoundingVolume , class TPrimitive , int Dims>
26
36
class BoundingVolumeHierarchy
27
37
{
28
38
public:
29
- using DerivedType = TDerived;
30
- using BoundingVolumeType = TBoundingVolume;
31
- using PrimitiveType = TPrimitive;
32
- static auto constexpr kDims = Dims;
39
+ using DerivedType = TDerived; // /< Actual type
40
+ using BoundingVolumeType = TBoundingVolume; // /< Type of bounding volumes
41
+ using PrimitiveType = TPrimitive; // /< Type of primitives
42
+ static auto constexpr kDims = Dims; // /< Embedding dimensionality
33
43
34
44
template <class TDerived2 , class TBoundingVolume2 , class TPrimitive2 , int Dims2>
35
45
friend class BoundingVolumeHierarchy ;
36
46
37
47
BoundingVolumeHierarchy () = default ;
38
48
39
49
/* *
40
- * @brief
41
- * @param maxPointsInLeaf
50
+ * @brief Construct the BVH from a set of primitives
51
+ * @param nPrimitives Number of primitives
52
+ * @param maxPointsInLeaf Maximum number of primitives in a leaf node
42
53
*/
43
54
void Construct (std::size_t nPrimitives, std::size_t maxPointsInLeaf = 10u );
44
55
/* *
45
- * @brief
46
- * @return
56
+ * @brief Returns the bounding volumes of this BVH
57
+ * @return Bounding volumes
47
58
*/
48
- std::vector<BoundingVolumeType> const & BoundingVolumes () const { return mBoundingVolumes ; }
59
+ auto BoundingVolumes () const -> std::vector<BoundingVolumeType> const &
60
+ {
61
+ return mBoundingVolumes ;
62
+ }
49
63
/* *
50
64
* @brief Returns the indices of the primitives contained in the bounding volume bvIdx
51
- * @param bvIdx
52
- * @return
65
+ * @param bvIdx Index of the bounding volume
66
+ * @return Range of indices of the primitives
53
67
*/
54
68
auto PrimitivesInBoundingVolume (Index bvIdx) const ;
55
69
/* *
56
- * @brief
70
+ * @brief Returns the indices of the primitives intersecting the bounding volume bv
71
+ * @tparam FIntersectsBoundingVolume Callable with signature `bool pred(BoundingVolume const&)`
72
+ * @tparam FIntersectsPrimitive Callable with signature `bool pred(Primitive const&)`
73
+ * primitive `p` is intersected.
57
74
* @param ibv Predicate pred(bv) evaluating to true if the bounding volume bv is intersected.
58
75
* @param ip Predicate pred(p) evaluating to true if the primitive p is intersected.
76
+ * @param reserve Estimated number of intersecting primitives to reserve in memory
59
77
* @return
60
78
*/
61
79
template <class FIntersectsBoundingVolume , class FIntersectsPrimitive >
@@ -65,38 +83,83 @@ class BoundingVolumeHierarchy
65
83
std::size_t reserve = 50ULL ) const ;
66
84
/* *
67
85
* @brief Obtains the k nearest neighbours (primitives of this BVH)
68
- * @tparam T
86
+ * @tparam FDistanceToBoundingVolume Callable with signature `Scalar pred(BoundingVolume
87
+ * const&)`
88
+ * @tparam FDistanceToPrimitive Callable with signature `Scalar pred(Primitive const&)`
69
89
* @param db Distance function d(b) between bounding volume b and user-owned shape
70
90
* @param dp Distance function d(p) between primitive p and user-owned shape
71
91
* @param K Number of nearest neighbours to query
72
- * @return
92
+ * @return Pair of vectors containing the indices of the nearest primitives and their
93
+ * distances
73
94
*/
74
95
template <class FDistanceToBoundingVolume , class FDistanceToPrimitive >
75
- std::pair<std::vector<Index>, std::vector<Scalar>>
96
+ auto
76
97
NearestPrimitivesTo (FDistanceToBoundingVolume&& db, FDistanceToPrimitive&& dp, std::size_t K)
77
- const ;
98
+ const -> std::pair<std::vector<Index>, std::vector<Scalar>> ;
78
99
79
100
/* *
80
101
* @brief Update the bounding volumes of this BVH
81
102
*/
82
103
void Update ();
83
104
84
105
// Static virtual functions (CRTP)
106
+
107
+ /* *
108
+ * @brief Returns the primitive at index p
109
+ * @note This function must be implemented by the derived class
110
+ * @param p Index of the primitive
111
+ * @return Primitive at index p
112
+ */
85
113
PrimitiveType Primitive (Index p) const
86
114
{
87
115
return static_cast <TDerived const *>(this )->Primitive (p);
88
116
}
117
+ /* *
118
+ * @brief Returns the location of the primitive
119
+ * @note This function must be implemented by the derived class
120
+ * @param primitive Primitive
121
+ * @return Location of the primitive
122
+ */
89
123
auto PrimitiveLocation (PrimitiveType const & primitive) const
90
124
{
91
125
return static_cast <TDerived const *>(this )->PrimitiveLocation (primitive);
92
126
}
127
+ /* *
128
+ * @brief Returns the bounding volume of the primitives in the range [first, last)
129
+ * @note This function must be implemented by the derived class
130
+ * @tparam RPrimitiveIndices Range of primitive indices
131
+ * @param primitiveIndexRange Range of primitive indices
132
+ * @return Bounding volume of the primitives
133
+ */
93
134
template <class RPrimitiveIndices >
94
135
BoundingVolumeType BoundingVolumeOf (RPrimitiveIndices&& primitiveIndexRange) const
95
136
{
96
137
return static_cast <TDerived const *>(this )->BoundingVolumeOf (primitiveIndexRange);
97
138
}
98
139
99
140
protected:
141
+ /* *
142
+ * @brief Returns the indices of the primitives overlapping between this BVH and another BVH
143
+ * @tparam TDerived2 Type of the other BVH
144
+ * @tparam TBoundingVolume2 Type of bounding volumes of the other BVH
145
+ * @tparam TPrimitive2 Type of primitives of the other BVH
146
+ * @tparam FBoundingVolumesOverlap Callable with signature `bool pred(BoundingVolume const&,
147
+ * BoundingVolume2 const&)`
148
+ * @tparam FPrimitivesOverlap Callable with signature `bool pred(Primitive const&, Primitive2
149
+ * const&)`
150
+ * @tparam FPrimitivesAreAdjacent Callable with signature `bool pred(Primitive const&,
151
+ * Primitive2 const&)`
152
+ * @tparam Dims2 Embedding dimensionality of the other BVH
153
+ * @param other Other BVH
154
+ * @param bvo Predicate pred(bv1, bv2) evaluating to true if the bounding volumes bv1 and bv2
155
+ * overlap
156
+ * @param po Predicate pred(p1, p2) evaluating to true if the primitives p1 and p2 overlap
157
+ * @param PrimitivesAreAdjacent Predicate pred(p1, p2) evaluating to true if the primitives p1
158
+ * and p2 are adjacent
159
+ * @param reserve Estimated number of overlapping primitives to reserve in memory
160
+ * @return `2 x |# overlaps|` matrix of overlapping primitive indices
161
+ *
162
+ */
100
163
template <
101
164
class TDerived2 ,
102
165
class TBoundingVolume2 ,
@@ -113,8 +176,8 @@ class BoundingVolumeHierarchy
113
176
[](PrimitiveType const & p1, TPrimitive2 const & p2) -> bool { return false ; },
114
177
std::size_t reserve = 50ULL ) const ;
115
178
116
- std::vector<BoundingVolumeType> mBoundingVolumes ;
117
- KdTree<kDims > mKdTree ;
179
+ std::vector<BoundingVolumeType> mBoundingVolumes ; // /< Bounding volumes of the BVH
180
+ KdTree<kDims > mKdTree ; // /< K-d tree used to store the primitives and the BVH tree
118
181
};
119
182
120
183
template <class TDerived , class TBoundingVolume , class TPrimitive , int Dims>
@@ -176,14 +239,14 @@ BoundingVolumeHierarchy<TDerived, TBoundingVolume, TPrimitive, Dims>::Primitives
176
239
intersectingPrimitives.push_back (idx);
177
240
}
178
241
}
179
- return false ; // /< Cannot visit deeper than a leaf node
242
+ return false ; // Cannot visit deeper than a leaf node
180
243
}
181
244
else
182
245
{
183
246
auto const bvIdxStl = static_cast <std::size_t >(bvIdx);
184
247
BoundingVolumeType const & bv = mBoundingVolumes [bvIdxStl];
185
- return ibv (bv); // /< Visit deeper if this bounding volume overlaps with the
186
- // /< queried shape
248
+ return ibv (bv); // Visit deeper if this bounding volume overlaps with the
249
+ // queried shape
187
250
}
188
251
});
189
252
@@ -192,11 +255,11 @@ BoundingVolumeHierarchy<TDerived, TBoundingVolume, TPrimitive, Dims>::Primitives
192
255
193
256
template <class TDerived , class TBoundingVolume , class TPrimitive , int Dims>
194
257
template <class FDistanceToBoundingVolume , class FDistanceToPrimitive >
195
- inline std::pair<std::vector<Index>, std::vector<Scalar>>
258
+ inline auto
196
259
BoundingVolumeHierarchy<TDerived, TBoundingVolume, TPrimitive, Dims>::NearestPrimitivesTo(
197
260
FDistanceToBoundingVolume&& db,
198
261
FDistanceToPrimitive&& dp,
199
- std::size_t K) const
262
+ std::size_t K) const -> std::pair<std::vector<Index>, std::vector<Scalar>>
200
263
{
201
264
std::vector<Index> neighbours{};
202
265
std::vector<Scalar> distances{};
@@ -206,11 +269,11 @@ BoundingVolumeHierarchy<TDerived, TBoundingVolume, TPrimitive, Dims>::NearestPri
206
269
enum class EQueueItem { Volume, Primitive };
207
270
struct QueueItem
208
271
{
209
- EQueueItem type; // /< Indicates if this QueueItem holds a primitive or a volume
210
- Index idx; // /< Index of the primitive, if this QueueItem holds a primitive, or index
211
- // /< of the node, if this QueueItem holds a volume (recall that node_idx =
212
- // /< bv_idx + 1)
213
- Scalar d; // /< Distance from this QueueItem to p
272
+ EQueueItem type; // Indicates if this QueueItem holds a primitive or a volume
273
+ Index idx; // Index of the primitive, if this QueueItem holds a primitive, or index
274
+ // of the node, if this QueueItem holds a volume (recall that node_idx =
275
+ // bv_idx + 1)
276
+ Scalar d; // Distance from this QueueItem to p
214
277
};
215
278
auto const MakeVolumeQueueItem = [&](Index bvIdx) {
216
279
auto const bvIdxStl = static_cast <std::size_t >(bvIdx);
@@ -297,7 +360,7 @@ BoundingVolumeHierarchy<TDerived, TBoundingVolume, TPrimitive, Dims>::Overlappin
297
360
298
361
using PrimitivePairType = std::pair<Index, Index>;
299
362
std::stack<PrimitivePairType> stack{};
300
- stack.push ({0 , 0 }); // /< Root bounding volumes of *this and other
363
+ stack.push ({0 , 0 }); // Root bounding volumes of *this and other
301
364
while (!stack.empty ())
302
365
{
303
366
auto const [n1, n2] = stack.top ();
@@ -370,4 +433,4 @@ BoundingVolumeHierarchy<TDerived, TBoundingVolume, TPrimitive, Dims>::Overlappin
370
433
} // namespace geometry
371
434
} // namespace pbat
372
435
373
- #endif // PBAT_GEOMETRY_BOUNDING_VOLUME_HIERARCHY_H
436
+ #endif // PBAT_GEOMETRY_BOUNDINGVOLUMEHIERARCHY_H
0 commit comments