215 __m128 h = _mm_castsi128_ps(_mm_set1_epi32(-1));
216 for (
size_t d = 0; d < D; ++d)
218 const __m128 pmin = _mm_set_ps1(box.corners[d][0]);
219 const __m128 pmax = _mm_set_ps1(box.corners[d][1]);
220 const __m128 hmin = _mm_cmp_ps(bounds.corners[d][0], pmax, _CMP_LE_OQ);
221 const __m128 hmax = _mm_cmp_ps(pmin, bounds.corners[d][1], _CMP_LE_OQ);
222 h = _mm_and_ps(h, hmin);
223 h = _mm_and_ps(h, hmax);
225 const int hitmask = _mm_movemask_ps(h);
231int overlaps(
const QAabb<double, D>& bounds,
const Aabb<double, D>& box)
233 __m256d h = _mm256_castsi256_pd(_mm256_set1_epi32(-1));
234 for (
size_t d = 0; d < D; ++d)
236 const __m256d pmin = _mm256_set1_pd(box.corners[d][0]);
237 const __m256d pmax = _mm256_set1_pd(box.corners[d][1]);
238 const __m256d hmin = _mm256_cmp_pd(bounds.corners[d][0], pmax, _CMP_LE_OQ);
239 const __m256d hmax = _mm256_cmp_pd(pmin, bounds.corners[d][1], _CMP_LE_OQ);
240 h = _mm256_and_pd(h, hmin);
241 h = _mm256_and_pd(h, hmax);
243 const int hitmask = _mm256_movemask_pd(h);
248int intersect(
const QAabb<float, D>& bounds,
const Ray<float, D>& ray,
float tMin,
float tMax,
float ts[4])
250 __m128 tmin = _mm_set_ps1(tMin);
251 __m128 tmax = _mm_set_ps1(tMax);
252 for (
size_t d = 0; d < D; ++d)
254 const __m128 support = _mm_set_ps1(ray.support[d]);
255 const __m128 invDir = _mm_set_ps1(ray.invDir[d]);
256 const bool sign = ray.sign[d];
257 const __m128 bmin = bounds.corners[d][
sign];
258 const __m128 bmax = bounds.corners[d][
sign ^ 1];
259 const __m128 dmin = _mm_mul_ps(_mm_sub_ps(bmin, support), invDir);
260 const __m128 dmax = _mm_mul_ps(_mm_sub_ps(bmax, support), invDir);
261 tmin = _mm_max_ps(dmin, tmin);
262 tmax = _mm_min_ps(dmax, tmax);
264 tmax = _mm_mul_ps(tmax, _mm_set_ps1(1 + 2 * num::NumTraits<float>::gamma(3)));
265 _mm_storeu_ps(ts, tmin);
266 __m128 h = _mm_cmp_ps(tmin, tmax, _CMP_LE_OQ);
267 const int hitmask = _mm_movemask_ps(h);
272int intersect(
const QAabb<double, D>& bounds,
const Ray<double, D>& ray,
double tMin,
double tMax,
double ts[4])
274 __m256d tmin = _mm256_set1_pd(tMin);
275 __m256d tmax = _mm256_set1_pd(tMax);
276 for (
size_t d = 0; d < D; ++d)
278 const __m256d support = _mm256_set1_pd(ray.support[d]);
279 const __m256d invDir = _mm256_set1_pd(ray.invDir[d]);
280 const bool sign = ray.sign[d];
281 const __m256d bmin = bounds.corners[d][
sign];
282 const __m256d bmax = bounds.corners[d][
sign ^ 1];
283 const __m256d dmin = _mm256_mul_pd(_mm256_sub_pd(bmin, support), invDir);
284 const __m256d dmax = _mm256_mul_pd(_mm256_sub_pd(bmax, support), invDir);
285 tmin = _mm256_max_pd(dmin, tmin);
286 tmax = _mm256_min_pd(dmax, tmax);
288 _mm256_storeu_pd(ts, tmin);
289 tmax = _mm256_mul_pd(tmax, _mm256_set1_pd(1 + 2 * num::NumTraits<double>::gamma(3)));
290 const __m256d h = _mm256_cmp_pd(tmin, tmax, _CMP_LE_OQ);
291 const int hitmask = _mm256_movemask_pd(h);
297void squaredDistance(
const QAabb<float, D>& bounds,
const Point<float, D>& point,
float sds[4])
299 const __m128 zero = _mm_setzero_ps();
300 __m128 sd = _mm_setzero_ps();
301 for (
size_t i = 0; i < D; ++i)
303 const __m128 p = _mm_set_ps1(point.x[i]);
304 const __m128 dmin = _mm_sub_ps(bounds.corners[i][0], p);
305 const __m128 dmax = _mm_sub_ps(p, bounds.corners[i][1]);
306 const __m128 d = _mm_max_ps(_mm_max_ps(dmin, dmax), zero);
307 const __m128 d2 = _mm_mul_ps(d, d);
308 sd = _mm_add_ps(sd, d2);
310 _mm_storeu_ps(sds, sd);
314void squaredDistance(
const QAabb<double, D>& bounds,
const Point<double, D>& point,
double sds[4])
316 const __m256d zero = _mm256_setzero_pd();
317 __m256d sd = _mm256_setzero_pd();
318 for (
size_t i = 0; i < D; ++i)
320 const __m256d p = _mm256_set1_pd(point.x[i]);
321 const __m256d dmin = _mm256_sub_pd(bounds.corners[i][0], p);
322 const __m256d dmax = _mm256_sub_pd(p, bounds.corners[i][1]);
323 const __m256d d = _mm256_max_pd(_mm256_max_pd(dmin, dmax), zero);
324 const __m256d d2 = _mm256_mul_pd(d, d);
325 sd = _mm256_add_pd(sd, d2);
327 _mm256_storeu_pd(sds, sd);
340template <
typename O,
typename OT,
typename SH>
341QbvhTree<O, OT, SH>::QbvhTree(TSplitHeuristics heuristics) :
342 SH(std::move(heuristics)),
343 aabb_(TObjectTraits::aabbEmpty()),
346 end_(new TObjectIterator),
353template <
typename O,
typename OT,
typename SH>
354QbvhTree<O, OT, SH>::QbvhTree(TObjectIterator first, TObjectIterator last, TSplitHeuristics heuristics):
355 SH(std::move(heuristics)),
356 aabb_(TObjectTraits::aabbEmpty()),
359 end_(new TObjectIterator(last)),
364 std::ptrdiff_t n = last - first;
367 LASS_THROW(
"QbvhTree: invalid range");
369 if (
static_cast<size_t>(n) >
static_cast<size_t>(Child::maxNode) + 1)
371 LASS_THROW(
"QbvhTree: too many objects");
374 inputs.reserve(
static_cast<size_t>(n));
375 for (TObjectIterator i = first; i != last; ++i)
377 inputs.emplace_back(TObjectTraits::objectAabb(i), i);
379 root_ = balance(inputs.begin(), inputs.end(), aabb_);
384template <
typename O,
typename OT,
typename SH>
385QbvhTree<O, OT, SH>::QbvhTree(TSelf&& other)
noexcept:
386 SH(std::forward<TSplitHeuristics>(other)),
387 aabb_(std::move(other.aabb_)),
388 nodes_(std::move(other.nodes_)),
389 objects_(std::move(other.objects_)),
390 end_(std::move(other.end_)),
391 root_(std::move(other.root_))
396template <
typename O,
typename OT,
typename SH>
399 TSplitHeuristics::operator=(std::forward<TSplitHeuristics>(other));
400 aabb_ = std::move(other.aabb_);
401 nodes_ = std::move(other.nodes_);
402 objects_ = std::move(other.objects_);
403 end_ = std::move(other.end_);
404 root_ = std::move(other.root_);
417template <
typename O,
typename OT,
typename SH>
433template <
typename O,
typename OT,
typename SH>
436 TSelf temp(first, last,
static_cast<const SH&
>(*
this));
444template <
typename O,
typename OT,
typename SH>
inline
445const typename QbvhTree<O, OT, SH>::TAabb
455template <
typename O,
typename OT,
typename SH>
458 if (
isEmpty() || !TObjectTraits::aabbContains(aabb_, point))
462 LASS_ASSERT(!root_.isEmpty());
463 return doContains(root_, point, info);
470template <
typename O,
typename OT,
typename SH>
471template <
typename OutputIterator>
inline
474 if (
isEmpty() || !TObjectTraits::aabbContains(aabb_, point))
478 LASS_ASSERT(!root_.isEmpty());
479 return doFind(root_, point, result, info);
486template <
typename O,
typename OT,
typename SH>
487template <
typename OutputIterator>
inline
490 if (
isEmpty() || !TObjectTraits::aabbIntersects(aabb_, box))
494 LASS_ASSERT(!root_.isEmpty());
495 return doFind(root_, box, result, info);
502template <
typename O,
typename OT,
typename SH>
503template <
typename OutputIterator>
506 const TVector invDir = TObjectTraits::vectorReciprocal(TObjectTraits::rayDirection(ray));
507 if (
isEmpty() || !volumeIntersects(aabb_, ray, invDir, tMin, tMax))
511 LASS_ASSERT(!root_.isEmpty());
512 return doFind(root_, ray, invDir, tMin, tMax, result, info);
519template <
typename O,
typename OT,
typename SH>
520typename QbvhTree<O, OT, SH>::TObjectIterator
523 const TVector dir = TObjectTraits::rayDirection(ray);
524 const TVector invDir = TObjectTraits::vectorReciprocal(dir);
526 if (
isEmpty() || !volumeIntersect(aabb_, ray, invDir, tRoot, tMin))
530 LASS_ASSERT(!root_.isEmpty());
531 return doIntersect(root_, ray, invDir, t, tMin, info);
538template <
typename O,
typename OT,
typename SH>
540 const TRay& ray, TParam tMin, TParam tMax,
const TInfo* info)
const
543 const TVector dir = TObjectTraits::rayDirection(ray);
544 const TVector invDir = TObjectTraits::vectorReciprocal(dir);
545 if (
isEmpty() || !volumeIntersects(aabb_, ray, invDir, tMin, tMax))
549 LASS_ASSERT(!root_.isEmpty());
550 return doIntersects(root_, ray, invDir, tMin, tMax, info);
557template <
typename O,
typename OT,
typename SH>
558const typename QbvhTree<O, OT, SH>::Neighbour
561 Neighbour nearest(*end_, std::numeric_limits<TValue>::infinity());
566 LASS_ASSERT(!root_.isEmpty());
567 doNearestNeighbour(root_, point, info, nearest);
592template <
class O,
class OT,
typename SH>
593template<
typename RandomIterator>
596 const TPoint& center, TParam maxRadius,
size_t maxCount, RandomIterator first,
const TInfo* info)
const
598 if (
isEmpty() || maxRadius == 0)
602 TValue squaredRadius = maxRadius * maxRadius;
603 LASS_ASSERT(!root_.isEmpty());
604 return doRangeSearch(root_, center, squaredRadius, maxCount, first, first, info);
611template <
typename O,
typename OT,
typename SH>
614 return objects_.empty();
624template <
typename O,
typename OT,
typename SH>
625const typename QbvhTree<O, OT, SH>::TObjectIterator
642template <
typename O,
typename OT,
typename SH>
646 std::swap(aabb_, other.aabb_);
647 nodes_.swap(other.nodes_);
648 objects_.swap(other.objects_);
649 end_.swap(other.end_);
650 std::swap(root_, other.root_);
657template <
typename O,
typename OT,
typename SH>
658typename QbvhTree<O, OT, SH>::Child
659QbvhTree<O, OT, SH>::balance(TInputIterator first, TInputIterator last, TAabb& bounds)
663 bounds = TObjectTraits::aabbEmpty();
667 LASS_ASSERT(nodes_.size() <=
static_cast<size_t>(Child::maxNode));
668 const TIndex index =
static_cast<TIndex
>(nodes_.size());
669 nodes_.emplace_back();
671 auto split0 = TSplitHeuristics::template split<OT>(first, last);
672 bounds = split0.aabb;
675 const auto count = last - first;
676 if (count <= Child::maxCount)
678 const TIndex frst =
static_cast<TIndex
>(objects_.size());
679 LASS_ASSERT(frst >= 0 && frst <= Child::maxObject);
680 for (TInputIterator i = first; i != last; ++i)
682 objects_.push_back(i->object);
684 LASS_ASSERT(objects_.size() <=
static_cast<size_t>(Child::maxObject) + 1);
685 return Child(frst,
static_cast<TIndex
>(count));
689 split0 = forceSplit(split0.aabb);
692 LASS_ASSERT(!split0.isLeaf());
693 nodes_[index].axis[0] =
static_cast<TAxis
>(split0.axis);
694 TInputIterator middle0 = std::partition(first, last, impl::Splitter<TObjectTraits>(split0));
695 if (middle0 == first || middle0 == last)
697 const std::ptrdiff_t halfSize = (last - first) / 2;
698 LASS_ASSERT(halfSize > 0);
699 middle0 = first + halfSize;
700 std::nth_element(first, middle0, last, impl::LessAxis<TObjectTraits>(split0.axis));
702 LASS_ASSERT(middle0 != first && middle0 != last);
704 auto split1 = TSplitHeuristics::template split<OT>(first, middle0);
707 const auto count = middle0 - first;
708 if (count <= Child::maxCount)
710 const TIndex frst =
static_cast<TIndex
>(objects_.size());
711 LASS_ASSERT(frst >= 0 && frst <= Child::maxObject);
712 for (TInputIterator i = first; i != middle0; ++i)
714 objects_.push_back(i->object);
716 LASS_ASSERT(objects_.size() <=
static_cast<size_t>(Child::maxObject) + 1);
717 Node& node = nodes_[index];
718 node.children[0] = Child(frst,
static_cast<TIndex
>(count));
719 node.children[1] = Child();
720 node.bounds.set(0, makeAabb(split1.aabb));
721 node.bounds.set(1, makeAabb(TObjectTraits::aabbEmpty()));
726 split1 = forceSplit(split1.aabb);
729 if (!split1.isLeaf())
731 TInputIterator middle1 = std::partition(first, middle0, impl::Splitter<TObjectTraits>(split1));
732 if (middle1 == first || middle1 == middle0)
734 const std::ptrdiff_t halfSize = (middle0 - first) / 2;
735 LASS_ASSERT(halfSize > 0);
736 middle1 = first + halfSize;
737 std::nth_element(first, middle1, middle0, impl::LessAxis<TObjectTraits>(split1.axis));
739 TAabb bounds0, bounds1;
740 Child child0 = balance(first, middle1, bounds0);
741 Child child1 = balance(middle1, middle0, bounds1);
742 Node& node = nodes_[index];
743 node.children[0] = child0;
744 node.children[1] = child1;
745 node.bounds.set(0, makeAabb(bounds0));
746 node.bounds.set(1, makeAabb(bounds1));
747 node.axis[1] =
static_cast<TAxis
>(split1.axis);
750 auto split2 = TSplitHeuristics::template split<OT>(middle0, last);
753 const auto count = last - middle0;
754 if (count <= Child::maxCount)
756 const TIndex frst =
static_cast<TIndex
>(objects_.size());
757 LASS_ASSERT(frst >= 0 && frst <= Child::maxObject);
758 for (TInputIterator i = middle0; i != last; ++i)
760 objects_.push_back(i->object);
762 LASS_ASSERT(objects_.size() <=
static_cast<size_t>(Child::maxObject) + 1);
763 Node& node = nodes_[index];
764 node.children[2] = Child(frst,
static_cast<TIndex
>(count));
765 node.children[3] = Child();
766 node.bounds.set(2, makeAabb(split2.aabb));
767 node.bounds.set(3, makeAabb(TObjectTraits::aabbEmpty()));
772 split2 = forceSplit(split2.aabb);
775 if (!split2.isLeaf())
777 TInputIterator middle2 = std::partition(middle0, last, impl::Splitter<TObjectTraits>(split2));
778 if (middle2 == middle0 || middle2 == last)
780 const std::ptrdiff_t halfSize = (last - middle0) / 2;
781 LASS_ASSERT(halfSize > 0);
782 middle2 = middle0 + halfSize;
783 std::nth_element(middle0, middle2, last, impl::LessAxis<TObjectTraits>(split2.axis));
785 TAabb bounds2, bounds3;
786 Child child2 = balance(middle0, middle2, bounds2);
787 Child child3 = balance(middle2, last, bounds3);
788 Node& node = nodes_[index];
789 node.children[2] = child2;
790 node.children[3] = child3;
791 node.bounds.set(2, makeAabb(bounds2));
792 node.bounds.set(3, makeAabb(bounds3));
793 node.axis[2] =
static_cast<TAxis
>(split2.axis);
796 Node& node = nodes_[index];
798 for (
size_t k = 0; k < 4; ++k)
800 node.usedMask |= node.children[k].isEmpty() ? 0 : 1 << k;
808template <
typename O,
typename OT,
typename SH>
809typename QbvhTree<O, OT, SH>::TSplitInfo
810QbvhTree<O, OT, SH>::forceSplit(
const TAabb& bounds)
812 const TPoint min = TObjectTraits::aabbMin(bounds);
813 const TPoint max = TObjectTraits::aabbMax(bounds);
815 TValue maxSize = TObjectTraits::coord(max, 0) - TObjectTraits::coord(min, 0);
816 for (
size_t k = 1; k < TObjectTraits::dimension; ++k)
818 const TValue size = TObjectTraits::coord(max, k) - TObjectTraits::coord(min, k);
825 const TValue x = (TObjectTraits::coord(min, axis) + TObjectTraits::coord(max, axis)) / 2;
826 return TSplitInfo(bounds, x, axis);
831template <
typename O,
typename OT,
typename SH>
832bool QbvhTree<O, OT, SH>::doContains(Child root,
const TPoint& point,
const TInfo* info)
const
834 const auto pnt = makePoint(point);
836 Child stack[stackSize_];
837 TIndex stackSize = 0;
838 stack[stackSize++] = root;
839 while (stackSize > 0)
841 const Child index = stack[--stackSize];
842 LASS_ASSERT(!index.isEmpty());
846 const TIndex first = index.first();
847 const TIndex last = first + index.count();
848 for (TIndex i = first; i != last; ++i)
850 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
851 if (TObjectTraits::objectContains(objects_[i], point, info))
859 LASS_ASSERT(index.isInternal());
860 LASS_ASSERT(index.node() < nodes_.size());
861 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
862 const Node& node = nodes_[index.node()];
864 const int hits = node.usedMask & impl::qbvh::contains(node.bounds, pnt);
865 for (
int k = 3; k >= 0; --k)
867 if (!(hits & (1 << k)))
871 const Child child = node.children[k];
876 if (stackSize < stackSize_)
878 stack[stackSize++] = child;
880 else if (doContains(child, point, info))
891template <
typename O,
typename OT,
typename SH>
892template <
typename OutputIterator>
893OutputIterator QbvhTree<O, OT, SH>::doFind(Child root,
const TPoint& point, OutputIterator result,
const TInfo* info)
const
895 const auto pnt = makePoint(point);
897 Child stack[stackSize_];
898 TIndex stackSize = 0;
899 stack[stackSize++] = root;
900 while (stackSize > 0)
902 const Child index = stack[--stackSize];
903 LASS_ASSERT(!index.isEmpty());
907 const TIndex first = index.first();
908 const TIndex last = first + index.count();
909 for (TIndex i = first; i != last; ++i)
911 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
912 if (TObjectTraits::objectContains(objects_[i], point, info))
914 *result++ = objects_[i];
920 LASS_ASSERT(index.isInternal());
921 LASS_ASSERT(index.node() < nodes_.size());
922 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
923 const Node& node = nodes_[index.node()];
925 const int hits = node.usedMask & impl::qbvh::contains(node.bounds, pnt);
926 for (
int k = 3; k >= 0; --k)
928 if (!(hits & (1 << k)))
932 const Child child = node.children[k];
937 if (stackSize < stackSize_)
939 stack[stackSize++] = child;
943 result = doFind(child, point, result, info);
951template <
typename O,
typename OT,
typename SH>
952template <
typename OutputIterator>
953OutputIterator QbvhTree<O, OT, SH>::doFind(Child root,
const TAabb& box, OutputIterator result,
const TInfo* info)
const
955 const auto bx = makeAabb(box);
957 Child stack[stackSize_];
958 TIndex stackSize = 0;
959 stack[stackSize++] = root;
960 while (stackSize > 0)
962 const Child index = stack[--stackSize];
963 LASS_ASSERT(!index.isEmpty());
967 const TIndex first = index.first();
968 const TIndex last = first + index.count();
969 for (TIndex i = first; i != last; ++i)
971 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
972 if (TObjectTraits::objectIntersects(objects_[i], box, info))
974 *result++ = objects_[i];
980 LASS_ASSERT(index.isInternal());
981 LASS_ASSERT(index.node() < nodes_.size());
982 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
983 const Node& node = nodes_[index.node()];
985 const int hits = node.usedMask & impl::qbvh::overlaps(node.bounds, bx);
986 for (
int k = 3; k >= 0; --k)
988 if (!(hits & (1 << k)))
992 const Child child = node.children[k];
997 if (stackSize < stackSize_)
999 stack[stackSize++] = child;
1003 result = doFind(child, box, result, info);
1012template <
typename O,
typename OT,
typename SH>
1013template <
typename OutputIterator>
1014OutputIterator QbvhTree<O, OT, SH>::doFind(Child root,
const TRay& ray,
const TVector& invDir, TParam tMin, TParam tMax, OutputIterator result,
const TInfo* info)
const
1016 const auto r = makeRay(ray);
1018 Child stack[stackSize_];
1019 TIndex stackSize = 0;
1020 stack[stackSize++] = root;
1021 while (stackSize > 0)
1023 const Child index = stack[--stackSize];
1024 LASS_ASSERT(!index.isEmpty());
1028 const TIndex first = index.first();
1029 const TIndex last = first + index.count();
1030 for (TIndex i = first; i != last; ++i)
1032 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
1033 if (TObjectTraits::objectIntersects(objects_[i], ray, tMin, tMax, info))
1035 *result++ = objects_[i];
1041 LASS_ASSERT(index.isInternal());
1042 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
1043 LASS_ASSERT(index.node() < nodes_.size());
1044 const Node& node = nodes_[index.node()];
1047 const int hits = node.usedMask & impl::qbvh::intersect(node.bounds, r, tMin, tMax, ts);
1048 for (
int k = 3; k >= 0; --k)
1050 if (!(hits & (1 << k)))
1054 const Child child = node.children[k];
1055 if (stackSize < stackSize_)
1057 stack[stackSize++] = child;
1061 result = doFind(child, ray, invDir, tMin, tMax, result, info);
1072template <
typename O,
typename OT,
typename SH>
1073typename QbvhTree<O, OT, SH>::TObjectIterator
1074QbvhTree<O, OT, SH>::doIntersect(Child root,
const TRay& ray,
const TVector& invDir, TReference t, TParam tMin,
const TInfo* info)
const
1076 const auto r = makeRay(ray);
1078 __m128i signs[dimension];
1079 for (
size_t i = 0; i < dimension; ++i)
1081 signs[i] = _mm_set1_epi32(r.sign[i] ? -1 : 0);
1090 Visit(Child index, TValue tNear): tNear(tNear), index(index) {}
1092 Visit stack[stackSize_];
1093 size_t stackSize = 0;
1094 stack[stackSize++] = Visit(root, tMin);
1095 TValue tBest = TNumTraits::infinity;
1096 TObjectIterator best = *end_;
1097 while (stackSize > 0)
1099 const Visit visit = stack[--stackSize];
1100 if (tBest <= visit.tNear)
1105 const Child index = visit.index;
1106 LASS_ASSERT(!index.isEmpty());
1110 const TIndex first = index.first();
1111 const TIndex last = first + index.count();
1112 for (TIndex i = first; i != last; ++i)
1114 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
1115 TValue tCandidate = 0;
1116 if (TObjectTraits::objectIntersect(objects_[i], ray, tCandidate, tMin, info))
1118 if (best == *end_ || tCandidate < tBest)
1128 LASS_ASSERT(index.isInternal());
1129 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
1130 LASS_ASSERT(index.node() < nodes_.size());
1131 const Node& node = nodes_[index.node()];
1134 const int hits = node.usedMask & impl::qbvh::intersect(node.bounds, r, tMin, tBest, ts);
1137 alignas(16)
int order[4];
1139 auto order_ = _mm_set_epi32(3, 2, 1, 0);
1140 const auto m0 = _mm_set_epi32(-1, -1, -1, -1);
1141 const auto m1 = _mm_set_epi32(0, 0, -1, -1);
1142 const auto m2 = _mm_set_epi32(-1, -1, 0, 0);
1143 const auto mask0 = _mm_and_si128(m0, signs[node.axis[0]]);
1144 const auto mask1 = _mm_and_si128(m1, signs[node.axis[1]]);
1145 const auto mask2 = _mm_and_si128(m2, signs[node.axis[2]]);
1146 const auto mask21 = _mm_or_si128(mask2, mask1);
1147 const auto order21 = _mm_shuffle_epi32(order_, 0xB1);
1148 order_ = _mm_blendv_epi8(order_, order21, mask21);
1149 const auto order0 = _mm_shuffle_epi32(order_, 0x4E);
1150 order_ = _mm_blendv_epi8(order_, order0, mask0);
1151 static_assert(
sizeof(order) ==
sizeof(order_));
1152 memcpy(order, &order_,
sizeof(order_));
1155 int order[4] = { 0, 1, 2, 3 };
1156 if (r.sign[node.axis[1]])
1158 std::swap(order[0], order[1]);
1160 if (r.sign[node.axis[2]])
1162 std::swap(order[2], order[3]);
1164 if (r.sign[node.axis[0]])
1166 std::swap(order[0], order[2]);
1167 std::swap(order[1], order[3]);
1172 for (
int k = 3; k >= 0; --k)
1174 const auto o = order[k];
1175 if (!(hits & (1 << o)))
1179 const Child child = node.children[o];
1180 if (stackSize < stackSize_)
1182 stack[stackSize++] = Visit(child, ts[o]);
1187 TObjectIterator b = doIntersect(child, ray, invDir, tb, tMin, info);
1188 if (b != *end_ && tb < tBest)
1205template <
typename O,
typename OT,
typename SH>
1206bool QbvhTree<O, OT, SH>::doIntersects(Child root,
const TRay& ray,
const TVector& invDir, TParam tMin, TParam tMax,
const TInfo* info)
const
1208 const auto r = makeRay(ray);
1210 Child stack[stackSize_];
1211 TIndex stackSize = 0;
1212 stack[stackSize++] = root;
1213 while (stackSize > 0)
1215 const Child index = stack[--stackSize];
1216 LASS_ASSERT(!index.isEmpty());
1220 const TIndex first = index.first();
1221 const TIndex last = first + index.count();
1222 for (TIndex i = first; i != last; ++i)
1224 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
1225 if (TObjectTraits::objectIntersects(objects_[i], ray, tMin, tMax, info))
1233 LASS_ASSERT(index.isInternal());
1234 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
1235 LASS_ASSERT(index.node() < nodes_.size());
1236 const Node& node = nodes_[index.node()];
1239 const int hits = node.usedMask & impl::qbvh::intersect(node.bounds, r, tMin, tMax, ts);
1240 for (
int k = 3; k >= 0; --k)
1242 if (!(hits & (1 << k)))
1246 const Child child = node.children[k];
1247 if (stackSize < stackSize_)
1249 stack[stackSize++] = child;
1251 else if (doIntersects(child, ray, invDir, tMin, tMax, info))
1264template <
typename T>
1265void sort4(
size_t order[4],
const T values[4])
1267 if (values[order[0]] > values[order[2]])
1269 std::swap(order[0], order[2]);
1271 if (values[order[1]] > values[order[3]])
1273 std::swap(order[1], order[3]);
1275 if (values[order[0]] > values[order[1]])
1277 std::swap(order[0], order[1]);
1279 if (values[order[2]] > values[order[3]])
1281 std::swap(order[2], order[3]);
1283 if (values[order[1]] > values[order[2]])
1285 std::swap(order[1], order[2]);
1287 LASS_ASSERT(values[order[0]] <= values[order[1]]);
1288 LASS_ASSERT(values[order[1]] <= values[order[2]]);
1289 LASS_ASSERT(values[order[2]] <= values[order[3]]);
1296template <
typename O,
typename OT,
typename SH>
1297void QbvhTree<O, OT, SH>::doNearestNeighbour(
1298 Child root,
const TPoint& target,
const TInfo* info, Neighbour& nearest)
const
1300 const auto pnt = makePoint(target);
1304 TValue squaredDistance;
1307 Visit(Child index, TValue squaredDistance): squaredDistance(squaredDistance), index(index) {}
1309 Visit stack[stackSize_];
1310 size_t stackSize = 0;
1311 stack[stackSize++] = Visit(root, 0);
1312 while (stackSize > 0)
1314 LASS_ASSERT(nearest.squaredDistance() >= 0);
1315 const Visit visit = stack[--stackSize];
1316 if (nearest.squaredDistance() <= visit.squaredDistance)
1321 const Child index = visit.index;
1322 LASS_ASSERT(!index.isEmpty());
1326 const auto first = index.first();
1327 const auto last = first + index.count();
1328 for (
auto i = first; i != last; ++i)
1330 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
1331 const TValue squaredDistance = TObjectTraits::objectSquaredDistance(objects_[i], target, info);
1332 if (squaredDistance < nearest.squaredDistance())
1334 nearest = Neighbour(objects_[i], squaredDistance);
1340 LASS_ASSERT(index.isInternal());
1341 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
1342 LASS_ASSERT(index.node() < nodes_.size());
1343 const Node& node = nodes_[index.node()];
1345 TValue squaredDistances[4];
1346 impl::qbvh::squaredDistance(node.bounds, pnt, squaredDistances);
1348 size_t order[4] = { 0, 1, 2, 3 };
1349 impl::qbvh::sort4(order, squaredDistances);
1352 for (
int k = 3; k >= 0; --k)
1354 const size_t o = order[k];
1355 const Child child = node.children[o];
1356 if (child.isEmpty())
1360 if (stackSize < stackSize_)
1362 stack[stackSize++] = Visit(child, squaredDistances[o]);
1366 doNearestNeighbour(child, target, info, nearest);
1374template <
typename O,
typename OT,
typename SH>
1375template <
typename RandomIterator>
1377QbvhTree<O, OT, SH>::doRangeSearch(
1378 Child root,
const TPoint& center, TReference squaredRadius,
size_t maxCount, RandomIterator first, RandomIterator last,
const TInfo* info)
const
1380 const auto pnt = makePoint(center);
1384 TValue squaredDistance;
1387 Visit(Child index, TValue squaredDistance): squaredDistance(squaredDistance), index(index) {}
1389 Visit stack[stackSize_];
1390 size_t stackSize = 0;
1391 stack[stackSize++] = Visit(root, 0);
1392 while (stackSize > 0)
1394 LASS_ASSERT(squaredRadius >= 0);
1395 const Visit visit = stack[--stackSize];
1396 if (squaredRadius <= visit.squaredDistance)
1401 const Child index = visit.index;
1402 LASS_ASSERT(!index.isEmpty());
1406 const auto frst = index.first();
1407 const auto lst = frst + index.count();
1408 for (
auto i = frst; i != lst; ++i)
1410 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
1411 const TValue squaredDistance = TObjectTraits::objectSquaredDistance(objects_[i], center, info);
1412 if (squaredDistance < squaredRadius)
1414 *last++ = Neighbour(objects_[i], squaredDistance);
1415 std::push_heap(first, last);
1416 LASS_ASSERT(last >= first);
1417 if (
static_cast<size_t>(last - first) > maxCount)
1419 std::pop_heap(first, last);
1421 squaredRadius = first->squaredDistance();
1428 LASS_ASSERT(index.isInternal());
1429 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
1430 LASS_ASSERT(index.node() < nodes_.size());
1431 const Node& node = nodes_[index.node()];
1433 TValue squaredDistances[4];
1434 impl::qbvh::squaredDistance(node.bounds, pnt, squaredDistances);
1436 size_t order[4] = { 0, 1, 2, 3 };
1437 impl::qbvh::sort4(order, squaredDistances);
1440 for (
int k = 3; k >= 0; --k)
1442 size_t o = order[k];
1443 const Child child = node.children[o];
1444 if (child.isEmpty())
1448 if (stackSize < stackSize_)
1450 stack[stackSize++] = Visit(child, squaredDistances[o]);
1454 last = doRangeSearch(child, center, squaredRadius, maxCount, first, last, info);
1464template <
typename O,
typename OT,
typename SH>
1465bool QbvhTree<O, OT, SH>::volumeIntersect(
const TAabb& box,
const TRay& ray,
const TVector& invDir, TReference t, TParam tMin)
const
1467 if (TObjectTraits::aabbContains(box, TObjectTraits::rayPoint(ray, tMin)))
1472 return TObjectTraits::aabbIntersect(box, ray, invDir, t, tMin);
1477template <
typename O,
typename OT,
typename SH>
1478bool QbvhTree<O, OT, SH>::volumeIntersects(
const TAabb& box,
const TRay& ray,
const TVector& invDir, TParam tMin, TParam tMax)
const
1481 return volumeIntersect(box, ray, invDir, t, tMin) && t <= tMax;
1486template <
typename O,
typename OT,
typename SH>
1487typename QbvhTree<O, OT, SH>::TPoint_
1488QbvhTree<O, OT, SH>::makePoint(
const TPoint& point)
1491 for (
size_t d = 0; d < dimension; ++d)
1493 result.x[d] = OT::coord(point, d);
1500template <
typename O,
typename OT,
typename SH>
1501typename QbvhTree<O, OT, SH>::TRay_
1502QbvhTree<O, OT, SH>::makeRay(
const TRay& ray)
1505 const auto support = OT::raySupport(ray);
1506 const auto direction = OT::rayDirection(ray);
1507 const auto invDir = TObjectTraits::vectorReciprocal(direction);
1508 for (
size_t d = 0; d < dimension; ++d)
1510 result.support[d] = OT::coord(support, d);
1511 result.invDir[d] = OT::coord(invDir, d);
1512 result.sign[d] = std::signbit(OT::coord(direction, d));
1519template <
typename O,
typename OT,
typename SH>
1520typename QbvhTree<O, OT, SH>::TAabb_
1521QbvhTree<O, OT, SH>::makeAabb(
const TAabb& aabb)
1524 const auto min = OT::aabbMin(aabb);
1525 const auto max = OT::aabbMax(aabb);
1526 for (
size_t d = 0; d < dimension; ++d)
1528 result.corners[d][0] = OT::coord(min, d);
1529 result.corners[d][1] = OT::coord(max, d);