in libraries/hvvr/shared/bvh.cpp [343:425]
uint32_t helpBuildBVH4(Box4*& out, const Box2* node, BoxPlus* parentCache, uint32_t first) {
// Post-order traversal: visit the children first.
BoxPlus cache[6];
uint32_t cacheSize = 0;
if (node->offset(0))
cacheSize += helpBuildBVH4(out, node + node->offset(0), cache + cacheSize, first);
else
cache[cacheSize++] = BoxPlus{node->boxes[0], first, first + node->size(0), 0, 0};
if (node->offset(1))
cacheSize += helpBuildBVH4(out, node + node->offset(1), cache + cacheSize, first + node->size(0));
else
cache[cacheSize++] =
BoxPlus{node->boxes[1], first + node->size(0), first + node->size(0) + node->size(1), 0, 0};
// If we get fewer than 4 nodes from our children, pass them to our parent.
if (cacheSize < 4) {
for (uint32_t i = 0; i < cacheSize; i++)
parentCache[i] = cache[i];
return cacheSize;
}
// We got 4 or more candidates from
uint32_t j0Best = 4;
uint32_t j1Best = 5;
if (cacheSize > 4) {
// Cache-size more than 4, find the set of 4 that produce the smallest box and pass the rest.
// Try to minimize the total depth by favoring passing nodes with higher depth.
std::sort(cache, cache + cacheSize, [](const BoxPlus& a, const BoxPlus& b) { return a.depth > b.depth; });
float minCost = Infinity;
if (cacheSize == 5) {
for (uint32_t j0 = 0; j0 < 5; j0++) {
Box box = Box::empty();
for (uint32_t i = 0; i < 5; i++)
if (i != j0)
box |= cache[i].box;
if (minCost > box.surfaceArea()) {
minCost = box.surfaceArea();
j0Best = j0;
}
}
} else {
for (uint32_t j1 = 1; j1 < 6; j1++)
for (uint32_t j0 = 0; j0 < j1; j0++) {
Box box = Box::empty();
for (uint32_t i = 0; i < 6; i++)
if (i != j0 && i != j1)
box |= cache[i].box;
if (minCost > box.surfaceArea()) {
minCost = box.surfaceArea();
j0Best = j0;
j1Best = j1;
}
}
}
}
// Allocate a new box from the output list.
BoxPlus* outBoxes = (--out)->boxes;
// Add the box we just created to our parent's cache.
BoxPlus* parent = parentCache++;
*parent = BoxPlus{Box::empty(), 0, 0, (uint32_t)(out - (Box4*)nullptr), 0};
for (uint32_t i = 0; i < cacheSize; i++) {
if (i == j0Best || i == j1Best) {
// Push the evected boxes into the parent's cache.
*parentCache++ = cache[i];
continue;
}
// Add these children to the allocated box and update the bounding box.
if (cache[i].offset)
cache[i].offset -= (uint32_t)(out - (Box4*)nullptr);
if (cache[i].depth + 1 > parent->depth)
parent->depth = cache[i].depth + 1;
parent->box |= cache[i].box;
*outBoxes++ = cache[i];
}
// Sort each box such that the leaves are first and nodes of the same type are sorted by surface area.
std::sort(out->boxes, out->boxes + 4, [](const BoxPlus& a, const BoxPlus& b) {
return (a.offset == 0 && b.offset != 0) ||
((a.offset == 0 || b.offset != 0) && a.box.surfaceArea() > b.box.surfaceArea());
});
// Return the total number of boxes we added to our parent's cache (our cache - 4 + 1 (the new node)).
return cacheSize - 3;
}