in libraries/hvvr/raycaster/scene_update.cpp [22:143]
void Raycaster::buildScene() {
uint32_t modelCount = uint32_t(_models.size());
if (modelCount == 0) {
_trianglesShade = std::vector<PrecomputedTriangleShade>();
_nodes = DynamicArray<BVHNode>(1);
_materials = std::vector<SimpleMaterial>();
// Create a root node that points to nothing.
_nodes[0].boxData.leafMask = 0xf;
for (size_t i = 0; i < 5; i++)
_nodes[0].boxData.leaf.triIndex[i] = 0;
return;
}
// Count the number of objects we're going to have to allocate.
uint32_t rootNodeCount = (modelCount + 1) / 3;
{
_vertexCount = 0;
uint32_t triangleCount = 0;
uint32_t nodeCount = rootNodeCount;
uint32_t materialCount = 0;
for (uint32_t modelIndex = 0; modelIndex < modelCount; modelIndex++) {
const Model& model = *(_models[modelIndex]);
const MeshData& meshData = model.getMesh();
_vertexCount += uint32_t(meshData.verts.size());
triangleCount += uint32_t(meshData.triShade.size());
nodeCount += uint32_t(meshData.nodes.size());
materialCount += uint32_t(meshData.materials.size());
}
_trianglesShade = std::vector<PrecomputedTriangleShade>(triangleCount);
_nodes = DynamicArray<BVHNode>(nodeCount);
_materials = std::vector<SimpleMaterial>(materialCount);
}
// Allocate the views.
std::vector<uint32_t> viewOffsets(_models.size());
uint32_t vertexOffset = 0;
uint32_t triOffset = 0;
uint32_t materialOffset = 0;
uint32_t nodeOffset = rootNodeCount;
for (uint32_t modelIndex = 0; modelIndex < modelCount; modelIndex++) {
const Model& model = *(_models[modelIndex]);
const MeshData& meshData = model.getMesh();
uint32_t materialCount = uint32_t(meshData.materials.size());
for (uint32_t n = 0; n < materialCount; n++) {
_materials[materialOffset + n] = meshData.materials[n];
}
uint32_t triCount = uint32_t(meshData.triShade.size());
for (uint32_t n = 0; n < triCount; n++) {
PrecomputedTriangleShade& triShade = _trianglesShade[triOffset + n];
triShade = meshData.triShade[n];
triShade.indices[0] += vertexOffset;
triShade.indices[1] += vertexOffset;
triShade.indices[2] += vertexOffset;
triShade.material += materialOffset;
}
// Initialize the BVH
uint32_t nodeCount = uint32_t(meshData.nodes.size());
viewOffsets[modelIndex] = nodeOffset;
for (uint32_t n = 0; n < nodeCount; n++) {
const TopologyNode& topoNode = meshData.nodes[n];
BVHNode& node = _nodes[nodeOffset + n];
node.boxData.leafMask = topoNode.leafMask;
node.boxData.leaf.triIndex[0] = triOffset + topoNode.getFirstTriangleIndex(0);
for (size_t k = 0; k < 4; k++) {
if (topoNode.isLeaf(k))
node.boxData.leaf.triIndex[1 + k] = triOffset + topoNode.getBoundTriangleIndex(k);
else
node.boxData.children.offset[k] = topoNode.getChildOffset(k);
}
}
vertexOffset += uint32_t(meshData.verts.size());
triOffset += triCount;
materialOffset += materialCount;
nodeOffset += nodeCount;
}
if (rootNodeCount > 0) {
// Initialize the root nodes to link the sub-trees together.
// We use a linear vector of child pointers initially because of the ease of access.
std::vector<BVHNode*> children(rootNodeCount * 4);
auto nextChild = children.data();
// Set the extra slots to nullptr (these will be empty leaves).
for (size_t i = children.size() - _models.size() - (rootNodeCount - 1); i != 0; --i)
*nextChild++ = nullptr;
// Set the pointers to the fixup nodes.
for (size_t i = 1, e = rootNodeCount; i < e; ++i)
*nextChild++ = _nodes.data() + i;
// Set the pointers to the entry points.
for (auto viewOffset : viewOffsets)
*nextChild++ = _nodes.data() + viewOffset;
if (nextChild != children.data() + children.size())
fail("Didn't update all of the children.");
// Convert the pointers in the children vector into offset in the actual fixup nodes.
for (size_t i = 0; i < rootNodeCount; i++) {
_nodes[i].boxData.leaf.triIndex[0] = 0;
_nodes[i].boxData.leafMask = 0;
for (size_t k = 0; k < 4; k++) {
if (children[4 * i + k] == nullptr) {
_nodes[i].boxData.leaf.triIndex[1 + k] = 0;
_nodes[i].boxData.leafMask |= 1 << k;
continue;
}
_nodes[i].boxData.children.offset[k] = uint32_t(children[4 * i + k] - (_nodes.data() + i));
}
}
}
}