1 #ifndef MOBILERT_ACCELERATORS_BVH_HPP 2 #define MOBILERT_ACCELERATORS_BVH_HPP 9 #include <boost/sort/spreadsort/spreadsort.hpp> 10 #include <glm/glm.hpp> 58 ::std::int32_t indexOffset_ {};
59 ::std::int32_t numPrimitives_ {};
64 rightshift(
const int longestAxis) noexcept : longestAxis_{longestAxis} { }
67 return ::boost::sort::spreadsort::float_mem_cast<float,
int>(node.
centroid_[this->longestAxis_]) >> offset;
73 lessthan(
const int longestAxis) noexcept : longestAxis_{longestAxis} { }
85 void build(::std::vector<T> &&primitives);
89 template<
typename Iterator>
92 template<
typename Iterator>
96 explicit BVH() =
default;
98 explicit BVH(::std::vector<T> &&primitives);
100 BVH(
const BVH &bvh) =
delete;
102 BVH(
BVH &&bvh) noexcept =
default;
127 if (primitives.empty()) {
128 this->
boxes_.emplace_back(BVHNode {});
129 LOG_WARN(
"Empty BVH for '",
typeid(T).name(),
"' without any primitives.");
132 const typename ::std::vector<T>::size_type numPrimitives {primitives.size()};
133 const typename ::std::vector<T>::size_type maxNodes {numPrimitives * 2 - 1};
134 this->
boxes_.resize(maxNodes);
135 LOG_INFO(
"Building BVH for '",
typeid(T).name(),
"' with '", numPrimitives,
"' primitives.");
136 build(::std::move(primitives));
137 LOG_INFO(
"Built BVH for '",
typeid(T).name(),
"' with '", this->
primitives_.size(),
"' primitives in '", this->
boxes_.size(),
"' boxes.");
150 ::std::vector<BVHNode> {}.swap(this->
boxes_);
162 ::std::int32_t currentBoxIndex {};
163 ::std::int32_t beginBoxIndex {};
164 const long long unsigned primitivesSize {primitives.size()};
165 ::std::int32_t endBoxIndex {
static_cast<::std::int32_t
> (primitivesSize)};
166 ::std::int32_t maxNodeIndex {};
168 ::std::array<::std::int32_t, StackSize> stackBoxIndex {};
169 ::std::array<::std::int32_t, StackSize> stackBoxBegin {};
170 ::std::array<::std::int32_t, StackSize> stackBoxEnd {};
172 ::std::array<::std::int32_t, StackSize>::iterator itStackBoxIndex {stackBoxIndex.begin()};
173 ::std::advance(itStackBoxIndex, 1);
175 ::std::array<::std::int32_t, StackSize>::iterator itStackBoxBegin {stackBoxBegin.begin()};
176 ::std::advance(itStackBoxBegin, 1);
178 ::std::array<::std::int32_t, StackSize>::iterator itStackBoxEnd {stackBoxEnd.begin()};
179 ::std::advance(itStackBoxEnd, 1);
181 const ::std::array<::std::int32_t, StackSize>::const_iterator itStackBoxIndexBegin {stackBoxIndex.cbegin()};
184 ::std::vector<BuildNode> buildNodes {};
185 buildNodes.reserve(static_cast<long unsigned> (primitivesSize));
186 for (::std::uint32_t i {}; i < primitivesSize; ++i) {
187 const T &primitive {primitives [i]};
188 AABB &&
box {primitive.getAABB()};
189 buildNodes.emplace_back(
BuildNode {::std::move(
box),
static_cast<::std::int32_t
> (i)});
193 const auto itCurrentBox {this->
boxes_.begin() + currentBoxIndex};
194 const ::std::int32_t boxPrimitivesSize {endBoxIndex - beginBoxIndex};
195 const auto itBegin {buildNodes.begin() + beginBoxIndex};
197 const auto itEnd {buildNodes.begin() + endBoxIndex};
200 const int longestAxis {
201 maxDist[0] >= maxDist[1] && maxDist[0] >= maxDist[2]
203 : maxDist[1] >= maxDist[0] && maxDist[1] >= maxDist[2]
210 const int numBuckets {10};
211 const ::glm::vec3 step {maxDist /
static_cast<float> (numBuckets)};
212 const float stepAxis {step[longestAxis]};
214 const float bucket1MaxLimit {startBox + stepAxis};
215 typename ::std::vector<BuildNode>::iterator itBucket {::std::partition(itBegin, itEnd,
217 return node.centroid_[longestAxis] < bucket1MaxLimit;
220 for (::std::int32_t bucketIndex {2}; bucketIndex < numBuckets; ++bucketIndex) {
221 const float bucketMaxLimit {startBox + stepAxis * bucketIndex};
222 itBucket = ::std::partition(::std::move(itBucket), itEnd,
224 return node.centroid_[longestAxis] < bucketMaxLimit;
230 itCurrentBox->box_ = itBegin->box_;
231 ::std::vector<AABB> boxes {itCurrentBox->box_};
232 boxes.reserve(static_cast<::std::uint32_t> (boxPrimitivesSize));
233 for (::std::int32_t i {beginBoxIndex + 1}; i < endBoxIndex; ++i) {
234 const AABB newBox {buildNodes[
static_cast<::std::uint32_t
> (i)].
box_};
236 boxes.emplace_back(newBox);
239 const int maxPrimitivesInBoxLeaf {4};
240 const bool isLeaf {boxPrimitivesSize <= maxPrimitivesInBoxLeaf};
242 itCurrentBox->indexOffset_ = beginBoxIndex;
243 itCurrentBox->numPrimitives_ = boxPrimitivesSize;
245 ::std::advance(itStackBoxIndex, -1);
246 currentBoxIndex = *itStackBoxIndex;
247 ::std::advance(itStackBoxBegin, -1);
248 beginBoxIndex = *itStackBoxBegin;
249 ::std::advance(itStackBoxEnd, -1);
250 endBoxIndex = *itStackBoxEnd;
252 const ::std::int32_t left {maxNodeIndex + 1};
253 const ::std::int32_t right {left + 1};
254 const ::std::int32_t splitIndex {
getSplitIndexSah(boxes.begin(), boxes.end())};
256 itCurrentBox->indexOffset_ = left;
257 maxNodeIndex = ::std::max(right, maxNodeIndex);
259 *itStackBoxIndex = right;
260 ::std::advance(itStackBoxIndex, 1);
261 *itStackBoxBegin = beginBoxIndex + splitIndex;
262 ::std::advance(itStackBoxBegin, 1);
263 *itStackBoxEnd = endBoxIndex;
264 ::std::advance(itStackBoxEnd, 1);
266 currentBoxIndex = left;
267 endBoxIndex = beginBoxIndex + splitIndex;
269 }
while(itStackBoxIndex > itStackBoxIndexBegin);
271 LOG_INFO(
"maxNodeIndex = ", maxNodeIndex);
273 this->
boxes_.shrink_to_fit();
274 ::std::vector<BVHNode> {this->
boxes_}.swap(this->
boxes_);
277 this->
primitives_.reserve(static_cast<long unsigned> (primitivesSize));
278 for (::std::uint32_t i {}; i < primitivesSize; ++i) {
280 const ::std::uint32_t oldIndex {
static_cast<::std::uint32_t
> (node.oldIndex_)};
281 this->
primitives_.emplace_back(::std::move(primitives[oldIndex]));
331 ::std::int32_t boxIndex {};
332 ::std::array<::std::int32_t, StackSize> stackBoxIndex {};
334 const ::std::array<::std::int32_t, StackSize>::const_iterator itBeginBoxIndex {stackBoxIndex.cbegin()};
335 ::std::array<::std::int32_t, StackSize>::iterator itStackBoxIndex {stackBoxIndex.begin()};
336 ::std::advance(itStackBoxIndex, 1);
338 const typename ::std::vector<BVHNode>::iterator itBoxes {this->
boxes_.begin()};
339 const typename ::std::vector<T>::iterator itPrimitives {this->
primitives_.begin()};
341 const BVHNode &node {*(itBoxes + boxIndex)};
342 if (node.box_.intersect(intersection.
ray_)) {
344 const ::std::int32_t numberPrimitives {node.numPrimitives_};
345 if (numberPrimitives > 0) {
346 for (::std::int32_t i {}; i < numberPrimitives; ++i) {
347 T &primitive {*(itPrimitives + node.indexOffset_ + i)};
348 const float lastDist {intersection.
length_};
349 intersection = primitive.intersect(intersection);
354 ::std::advance(itStackBoxIndex, -1);
355 boxIndex = *itStackBoxIndex;
357 const ::std::int32_t left {node.indexOffset_};
358 const ::std::int32_t right {node.indexOffset_ + 1};
359 const BVHNode &childLeft {*(itBoxes + left)};
360 const BVHNode &childRight {*(itBoxes + right)};
362 const bool traverseLeft {childLeft.box_.intersect(intersection.
ray_)};
363 const bool traverseRight {childRight.box_.intersect(intersection.
ray_)};
365 if (!traverseLeft && !traverseRight) {
366 ::std::advance(itStackBoxIndex, -1);
367 boxIndex = *itStackBoxIndex;
369 boxIndex = (traverseLeft) ? left : right;
370 if (traverseLeft && traverseRight) {
371 *itStackBoxIndex = right;
372 ::std::advance(itStackBoxIndex, 1);
378 ::std::advance(itStackBoxIndex, -1);
379 boxIndex = *itStackBoxIndex;
382 }
while (itStackBoxIndex > itBeginBoxIndex);
397 template<
typename Iterator>
399 const long numberBoxes {
static_cast<long>(itEnd - itBegin)};
400 const Iterator itBoxes {itBegin};
401 const long numBoxes {numberBoxes - 1};
402 const ::std::uint32_t sizeUnsigned {
static_cast<::std::uint32_t
> (numBoxes)};
404 ::std::vector<float> leftArea (sizeUnsigned);
405 AABB leftBox {*itBoxes};
406 const ::std::vector<float>::iterator itLeftArea {leftArea.begin()};
407 *itLeftArea = leftBox.getSurfaceArea();
408 for (::std::int32_t i {1}; i < numBoxes; ++i) {
410 *(itLeftArea + i) = leftBox.getSurfaceArea();
413 ::std::vector<float> rightArea (sizeUnsigned);
414 AABB rightBox {*(itBoxes + numBoxes)};
415 const ::std::vector<float>::iterator itRightArea {rightArea.begin()};
416 *(itRightArea + numBoxes - 1) = rightBox.getSurfaceArea();
417 for (
long i {numBoxes - 2}; i >= 0; --i) {
419 *(itRightArea + i) = rightBox.getSurfaceArea();
422 ::std::int32_t splitIndex {1};
423 float minSah {*(itLeftArea) + numBoxes * *(itRightArea)};
424 for (::std::int32_t i {1}; i < numBoxes; ++i) {
425 const ::std::int32_t nextSplit {i + 1};
426 const long numBoxesLeft {nextSplit};
427 const long numBoxesRight {numberBoxes - numBoxesLeft};
428 const float areaLeft {*(itLeftArea + i)};
429 const float areaRight {*(itRightArea + i)};
430 const float leftSah {numBoxesLeft * areaLeft};
431 const float rightSah {numBoxesRight * areaRight};
432 const float sah {leftSah + rightSah};
434 splitIndex = nextSplit;
450 template<
typename Iterator>
452 AABB maxBox {itBegin->box_.
getPointMin(), itBegin->box_.getPointMax()};
454 for (Iterator it {itBegin + 1}; it < itEnd; ::std::advance(it, 1)) {
476 #endif //MOBILERT_ACCELERATORS_BVH_HPP bool operator()(const BuildNode &node1, const BuildNode &node2) const
Definition: BVH.hpp:75
::std::vector< T > primitives_
Definition: BVH.hpp:82
#define LOG_WARN(...)
Definition: Utils.hpp:48
Ray ray_
Definition: Intersection.hpp:27
Intersection intersect(Intersection intersection)
Definition: BVH.hpp:327
void build(::std::vector< T > &&primitives)
Definition: BVH.hpp:161
int operator()(const BuildNode &node, const unsigned offset) const
Definition: BVH.hpp:66
#define LOG_INFO(...)
Definition: Utils.hpp:43
::std::int32_t getSplitIndexSah(Iterator itBegin, Iterator itEnd)
Intersection shadowTrace(Intersection intersection)
Definition: BVH.hpp:309
const ::std::vector< T > & getPrimitives() const
Definition: BVH.hpp:469
lessthan(const int longestAxis) noexcept
Definition: BVH.hpp:73
float length_
Definition: Intersection.hpp:19
Definition: Intersection.hpp:14
::glm::vec3 centroid_
Definition: BVH.hpp:30
AABB getSurroundingBox(Iterator itBegin, Iterator itEnd)
Definition: BVH.hpp:451
::std::vector< BVHNode > boxes_
Definition: BVH.hpp:81
::std::int32_t oldIndex_
Definition: BVH.hpp:31
::glm::vec3 getPointMax() const
Definition: AABB.cpp:101
::glm::vec3 getCentroid() const
Definition: AABB.cpp:81
AABB surroundingBox(const AABB &box1, const AABB &box2)
Definition: AABB.cpp:113
AABB box_
Definition: BVH.hpp:29
int longestAxis_
Definition: BVH.hpp:72
~BVH()
Definition: BVH.hpp:146
BuildNode(AABB &&box, const ::std::int32_t oldIndex)
Definition: BVH.hpp:45
bool shadowTrace_
Definition: Ray.hpp:45
BVH & operator=(const BVH &bvh)=delete
int longestAxis_
Definition: BVH.hpp:63
Intersection trace(Intersection intersection)
Definition: BVH.hpp:294
::glm::vec3 getPointMin() const
Definition: AABB.cpp:92
rightshift(const int longestAxis) noexcept
Definition: BVH.hpp:64
const AABB box
Definition: TestPlane.cpp:26