File indexing completed on 2026-10-27 09:40:39
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009 #include "corecel/cont/IdStack.hh"
0010 #include "corecel/math/Algorithms.hh"
0011 #include "orange/OrangeTypes.hh"
0012
0013 #include "BvhView.hh"
0014 #include "../BoundingBoxUtils.hh"
0015 #include "../univ/detail/Types.hh"
0016
0017 #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
0018 # if __GNUC__ < 9
0019
0020 # define CELER_GCC8_BUGGY_CONSTEXPR 1
0021 # else
0022 # define CELER_GCC8_BUGGY_CONSTEXPR 0
0023 # endif
0024 #else
0025 # define CELER_GCC8_BUGGY_CONSTEXPR 0
0026 #endif
0027
0028 namespace celeritas
0029 {
0030 namespace detail
0031 {
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049 class BvhIntersectingVolFinder
0050 {
0051 public:
0052
0053
0054 using Storage = NativeCRef<BvhTreeData>;
0055
0056 struct Ray
0057 {
0058 Real3 const& pos;
0059 Real3 const& dir;
0060 };
0061
0062
0063
0064 inline CELER_FUNCTION BvhIntersectingVolFinder(BvhTreeRecord const& tree,
0065 Storage const& storage);
0066
0067
0068
0069 template<class F>
0070 inline CELER_FUNCTION Intersection operator()(
0071 Ray ray, F&& visit_vol, real_type max_search_dist) const;
0072
0073 private:
0074
0075 BvhView view_;
0076
0077
0078
0079
0080
0081 inline CELER_FUNCTION bool visit_bbox(
0082 FastBBox const& bbox, Ray ray, real_type min_dist) const;
0083
0084
0085
0086 template<class F>
0087 inline CELER_FUNCTION Intersection visit_leaf(BvhNodeId leaf_node_id,
0088 Intersection intersection,
0089 F&& visit_vol) const;
0090
0091
0092 template<class F>
0093 inline CELER_FUNCTION Intersection visit_inf_vols(
0094 Intersection intersection, F&& visit_vol) const;
0095 };
0096
0097
0098
0099
0100
0101
0102
0103 CELER_FUNCTION BvhIntersectingVolFinder::BvhIntersectingVolFinder(
0104 BvhTreeRecord const& tree, BvhIntersectingVolFinder::Storage const& storage)
0105 : view_(tree, storage)
0106 {
0107 CELER_EXPECT(tree);
0108 }
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122 template<class F>
0123 CELER_FUNCTION auto BvhIntersectingVolFinder::operator()(
0124 BvhIntersectingVolFinder::Ray ray,
0125 F&& visit_vol,
0126 real_type max_search_dist) const -> Intersection
0127 {
0128 using Side = BvhInternalNode::Side;
0129
0130 Intersection intersection{OnLocalSurface{}, max_search_dist};
0131
0132
0133 using StackT = IdStack<BvhNodeId, max_bvh_depth - 1>;
0134 BvhNodeId stack_spill_[StackT::spill_extent];
0135 StackT stack{stack_spill_};
0136 #if !CELER_GCC8_BUGGY_CONSTEXPR
0137
0138 static_assert(stack.capacity() == max_bvh_depth);
0139 #endif
0140 stack.push(BvhNodeId{0});
0141
0142 while (!stack.empty())
0143 {
0144 if (!view_.is_internal(stack.top()))
0145 {
0146 intersection
0147 = this->visit_leaf(stack.top(), intersection, visit_vol);
0148 stack.pop();
0149 continue;
0150 }
0151
0152 auto const& node = view_.inner_node(stack.top());
0153 stack.pop();
0154 int ax = to_int(node.axis());
0155
0156
0157
0158 FastBBox first_bbox = node.bbox(Side::left);
0159 BvhNodeId first_child = node.child(Side::left);
0160 FastBBox second_bbox = node.bbox(Side::right);
0161 BvhNodeId second_child = node.child(Side::right);
0162
0163 if (ray.pos[ax] > node.bbox(Side::right).lower()[ax])
0164 {
0165 trivial_swap(first_bbox, second_bbox);
0166 trivial_swap(first_child, second_child);
0167 }
0168
0169
0170 if (this->visit_bbox(second_bbox, ray, intersection.distance))
0171 {
0172 stack.push(second_child);
0173 }
0174 if (this->visit_bbox(first_bbox, ray, intersection.distance))
0175 {
0176 stack.push(first_child);
0177 }
0178 }
0179
0180 return this->visit_inf_vols(intersection, visit_vol);
0181 }
0182
0183
0184
0185
0186
0187
0188 CELER_FUNCTION bool BvhIntersectingVolFinder::visit_bbox(
0189 FastBBox const& bbox, Ray ray, real_type min_dist) const
0190 {
0191 return intersects_segment(bbox, ray.pos, ray.dir, min_dist);
0192 }
0193
0194
0195
0196
0197
0198 template<class F>
0199 CELER_FUNCTION auto BvhIntersectingVolFinder::visit_leaf(
0200 BvhNodeId leaf_node_id, Intersection min_intersection, F&& visit_vol) const
0201 -> Intersection
0202 {
0203 for (auto id : view_.leaf_vol_ids(leaf_node_id))
0204 {
0205 auto intersection = visit_vol(id, min_intersection.distance);
0206 if (intersection)
0207 {
0208 CELER_ASSERT(intersection.distance <= min_intersection.distance);
0209 min_intersection = intersection;
0210 }
0211 }
0212 return min_intersection;
0213 }
0214
0215
0216
0217
0218
0219 template<class F>
0220 CELER_FUNCTION auto BvhIntersectingVolFinder::visit_inf_vols(
0221 Intersection min_intersection, F&& visit_vol) const -> Intersection
0222 {
0223 for (auto id : view_.inf_vol_ids())
0224 {
0225 auto intersection = visit_vol(id, min_intersection.distance);
0226 if (intersection)
0227 {
0228 CELER_ASSERT(intersection.distance <= min_intersection.distance);
0229 min_intersection = intersection;
0230 }
0231 }
0232 return min_intersection;
0233 }
0234
0235
0236 }
0237 }