Ejemplo n.º 1
0
    KDTreeNode *KDTree::recursiveBuild(const std::vector<KDTreeNodeRef>& objectList, AABB &aabb, int currentDepth) {
        KDTreeNode *res = new KDTreeNode(aabb);
        if (terminateBuild(objectList, aabb, currentDepth)) {
            for (const KDTreeNodeRef & nodeRef : objectList) {
                res->objects.push_back(nodeRef);
            }
            return res;
        }
        findPlane(objectList, aabb, currentDepth, res);

        // split aabb with splitting plane
        AABB leftAabb(aabb);
        leftAabb.max[res->splittingAxis] = res->splittingPlane;
        AABB rightAabb(aabb);
        rightAabb.min[res->splittingAxis] = res->splittingPlane;

        vector < KDTreeNodeRef > leftObjects;
        vector < KDTreeNodeRef > rightObjects;
        for (const KDTreeNodeRef & nodeRef : objectList) {
            const AABB objectAABB = nodeRef.getAABB();
            if (leftAabb.intersect(objectAABB)) {
                leftObjects.push_back(nodeRef);
            }
            if (rightAabb.intersect(objectAABB)) {
                rightObjects.push_back(nodeRef);
            }
        }
        currentDepth++;
        res->leftChild = recursiveBuild(leftObjects, leftAabb, currentDepth);
        res->rightChild = recursiveBuild(rightObjects, rightAabb, currentDepth);
        return res;
    }
Ejemplo n.º 2
0
static void recursiveBuild(BuildResult &result, NaiveBvhNode &dst, uint32 start, uint32 end,
        PrimVector &prims, const Box3f &geomBox, const Box3f &centroidBox, uint32 branchFactor)
{
    result = BuildResult{1, 1};

    dst.bbox() = geomBox;
    uint32 numPrims = end - start + 1;

    if (numPrims == 1) {
        // Single primitive, just create a leaf node
        dst.setId(prims[start].id());
    } else if (numPrims <= branchFactor) {
        // Few primitives, create internal node with numPrims children
        result.nodeCount += numPrims;
        for (uint32 i = start; i <= end; ++i)
            dst.setChild(i - start, new NaiveBvhNode(narrow(prims[i].box()), prims[i].id()));
    } else {
        // Many primitives: Setup SAH split
        uint32 starts[4], ends[4];
        Box3f geomBoxes[4], centroidBoxes[4];
        starts       [0] = start;
        ends         [0] = end;
        geomBoxes    [0] = geomBox;
        centroidBoxes[0] = centroidBox;

        // Perform the split (potentially in parallel)
        uint32 childCount = sahSplit(starts, ends, geomBoxes, centroidBoxes, prims, branchFactor);

        // TODO: Use pool allocator?
        for (unsigned i = 0; i < childCount; ++i)
            dst.setChild(i, new NaiveBvhNode());

        if (numPrims <= 32*1024) {
            // Perform single threaded recursive build for small workloads
            for (unsigned i = 0; i < childCount; ++i) {
                BuildResult recursiveResult;
                recursiveBuild(recursiveResult, *dst.child(i), starts[i], ends[i],
                        prims, geomBoxes[i], centroidBoxes[i], branchFactor);
                result.nodeCount += recursiveResult.nodeCount;
                result.depth = max(result.depth, recursiveResult.depth + 1);
            }
        } else {
            // Enqueue parallel build for large workloads
            BuildResult results[4];
            std::shared_ptr<TaskGroup> group = ThreadUtils::pool->enqueue([&](uint32 i, uint32, uint32) {
                recursiveBuild(results[i], *dst.child(i), starts[i], ends[i],
                        prims, geomBoxes[i], centroidBoxes[i], branchFactor);
            }, childCount);
            // Do some work while we wait
            ThreadUtils::pool->yield(*group);

            // Serial reduce
            for (unsigned i = 0; i < childCount; ++i) {
                result.nodeCount += results[i].nodeCount;
                result.depth = max(result.depth, results[i].depth + 1);
            }
        }
    }
}
Ejemplo n.º 3
0
//Necesito crear una función auxiliar para poder hacer recursión recibiendo el ziptable y el bitchain por parámetro.
ZipTable recursiveBuild(ZipTable zt, HuffmanTree t, BitChain bc) {
    if(isLeaf(t))
        add(zt, t -> caracter, bc);
    else {
        append(bc, false);
        recursiveBuild(zt, t -> izq, bc);
        remove(bc);
        append(bc, true);
        recursiveBuild(zt, t -> der, bc);
        remove(bc);
    }
    return zt;
}
Ejemplo n.º 4
0
 void recursiveBuild(SegmentTreeNode *parent){
     if (parent->start == parent->end) {
         return;
     }
  		 
     SegmentTreeNode *left = new SegmentTreeNode(parent->start, 
                                                 (parent->start + parent->end) / 2);
     SegmentTreeNode *right = new SegmentTreeNode((parent->start + parent->end) / 2 + 1,
                                                     parent->end);
                                                     
     parent->left = left;
     parent->right = right;
     recursiveBuild(parent->left);
     recursiveBuild(parent->right);
 }
Ejemplo n.º 5
0
    void recursiveBuild(uint32_t nodeIndex, uint32_t start, uint32_t end, uint32_t* indices,
                        PositionFunctor getPosition, uint32_t& nextFreeNode) {
        if(start + 1 == end) {
            // One node to process, it's a  leaf
            m_Nodes[nodeIndex].setAsLeaf();

            m_NodesData[nodeIndex].m_nIndex = indices[start];
            m_NodesData[nodeIndex].m_Position = getPosition(indices[start]);

            return;
        }

        // Compute the bounding box of the data
        BBox3f bound;
        for(uint32_t i = start; i != end; ++i) {
            bound += getPosition(indices[i]);
        }
        // The split axis is the one with maximal extent for the data
        uint32_t splitAxis = maxComponent(abs(bound.size()));
        uint32_t splitIndex = (start + end) / 2;
        // Reorganize the pointers such that the middle element is the middle element on the split axis
        std::nth_element(indices + start, indices + splitIndex, indices + end,
                         [splitAxis, &getPosition](uint32_t lhs, uint32_t rhs) -> bool {
                            float v1 = getPosition(lhs)[splitAxis];
                            float v2 = getPosition(rhs)[splitAxis];
                            return v1 == v2 ? lhs < rhs : v1 < v2;
                         });
        float splitPosition = getPosition(indices[splitIndex])[splitAxis];
        m_Nodes[nodeIndex].setAsInnerNode(splitPosition, splitAxis);
        m_NodesData[nodeIndex].m_nIndex = indices[splitIndex];
        m_NodesData[nodeIndex].m_Position = getPosition(indices[splitIndex]);

        // Build the left subtree
        if(start < splitIndex) {
            m_Nodes[nodeIndex].m_bHasLeftChild = true;
            uint32_t childIndex = nextFreeNode++;
            recursiveBuild(childIndex, start, splitIndex, indices, getPosition, nextFreeNode);
        }

        // Build the right subtree
        if(splitIndex + 1 < end) {
            m_Nodes[nodeIndex].m_nRightChildIndex = nextFreeNode++;
            recursiveBuild(m_Nodes[nodeIndex].m_nRightChildIndex, splitIndex + 1, end, indices, getPosition, nextFreeNode);
        }
    }
Ejemplo n.º 6
0
BAH::BAHNode *BAH::recursiveBuild(std::vector<BAHElement> &buildData,
                                  uint32_t start, uint32_t end,
                                  uint32_t *totalNodes,
                                  std::vector<uint32_t> &orderedElements) {
  (*totalNodes)++;
  BAHNode *node = new BAHNode();
  ponos::bbox2 bbox;
  for (uint32_t i = start; i < end; ++i)
    bbox = ponos::make_union(bbox, buildData[i].bounds);
  // compute all bounds
  uint32_t nElements = end - start;
  if (nElements == 1) {
    // create leaf node
    uint32_t firstElementOffset = orderedElements.size();
    for (uint32_t i = start; i < end; i++) {
      uint32_t elementNum = buildData[i].ind;
      orderedElements.emplace_back(elementNum);
    }
    node->initLeaf(firstElementOffset, nElements, bbox);
  } else {
    // compute bound of primitives
    ponos::bbox2 centroidBounds;
    for (uint32_t i = start; i < end; i++)
      centroidBounds = ponos::make_union(centroidBounds, buildData[i].centroid);
    int dim = centroidBounds.maxExtent();
    // partition primitives
    uint32_t mid = (start + end) / 2;
    if (centroidBounds.upper[dim] == centroidBounds.lower[dim]) {
      node->initInterior(
          dim,
          recursiveBuild(buildData, start, mid, totalNodes, orderedElements),
          recursiveBuild(buildData, mid, end, totalNodes, orderedElements));
      return node;
    }
    // partition into equally sized subsets
    std::nth_element(&buildData[start], &buildData[mid],
                     &buildData[end - 1] + 1, ComparePoints(dim));
    node->initInterior(
        dim, recursiveBuild(buildData, start, mid, totalNodes, orderedElements),
        recursiveBuild(buildData, mid, end, totalNodes, orderedElements));
  }
  return node;
}
Ejemplo n.º 7
0
 /**
  *@param start, end: Denote an segment / interval
  *@return: The root of Segment Tree
  */
 SegmentTreeNode * build(int start, int end) {
     // write your code here
     if(end < start){
         return NULL;
     }
     
     SegmentTreeNode *root = new SegmentTreeNode(start, end);
     recursiveBuild(root);
     return root;
 }
Ejemplo n.º 8
0
BVHBuildNode *BVH::recursiveBuild(int start, int end, int *numTotalNodes)
{
	AABoundingBox bbox;
	for(int i=start; i<end; i++){
		bbox.join(m_buildData[i].m_bbox);
	}
	BVHBuildNode *node = new BVHBuildNode();
    (*numTotalNodes)++;

	int numTriangles = end - start;

	if(numTriangles == 1){
		createLeafNode(start,end,bbox,node, numTotalNodes);
	}
	else{
		AABoundingBox bboxCentroids;
		for(int i=start; i<end; i++){
			bboxCentroids.join(m_buildData[i].m_centroid);
		}
		int dim = bboxCentroids.getMaximumExtent();
		if(bboxCentroids.min(dim) == bboxCentroids.max(dim)){
			createLeafNode(start,end,bbox,node,numTotalNodes);
		}
        else{
            float splitCost;
            int splitBucket;
            findSAHSplit(dim,start,end,bboxCentroids,bbox, &splitCost, &splitBucket);
            if(numTriangles > 6 || splitCost < numTriangles){
                BVHTriangleInfo *midPtr = std::partition(&m_buildData[start], &m_buildData[end], CompareToBucket(dim, splitBucket, 12, bboxCentroids));
                int mid = midPtr - &m_buildData[0];
                if(mid == start || mid == end){
                    mid = start+1;
                }
                node->initInterior(dim, recursiveBuild(start,mid,numTotalNodes), recursiveBuild(mid,end,numTotalNodes));
            }
            else{
                createLeafNode(start,end,bbox,node,numTotalNodes);
            }
        }
	}
	
	return node;
}
Ejemplo n.º 9
0
void
buildKDTree(const GeDynamicArray<Vector> &points, KDNode **nodes, Random &rng)
{
	Sorter sorter;
	Int32 *pnts = NewMemClear(Int32,points.GetCount());
	Int32 numPoints = points.GetCount();
	for(Int32 i=0;i<numPoints;i++){
		pnts[i] = i;
	}
	*nodes = recursiveBuild(points,pnts,numPoints,rng,0,sorter);
}
Ejemplo n.º 10
0
Archivo: bvh.cpp Proyecto: AI42/OM3D
// BVHAccel Method Definitions
BVHAccel::BVHAccel(const vector<Reference<Primitive> > &p,
                   uint32_t mp, const string &sm) {
    maxPrimsInNode = min(255u, mp);
    for (uint32_t i = 0; i < p.size(); ++i)
        p[i]->FullyRefine(primitives);
    if (sm == "sah")         splitMethod = SPLIT_SAH;
    else if (sm == "middle") splitMethod = SPLIT_MIDDLE;
    else if (sm == "equal")  splitMethod = SPLIT_EQUAL_COUNTS;
    else {
        Warning("BVH split method \"%s\" unknown.  Using \"sah\".",
                sm.c_str());
        splitMethod = SPLIT_SAH;
    }

    if (primitives.size() == 0) {
        nodes = NULL;
        return;
    }
    // Build BVH from _primitives_
    PBRT_BVH_STARTED_CONSTRUCTION(this, primitives.size());

    // Initialize _buildData_ array for primitives
    vector<BVHPrimitiveInfo> buildData;
    buildData.reserve(primitives.size());
    for (uint32_t i = 0; i < primitives.size(); ++i) {
        BBox bbox = primitives[i]->WorldBound();
        buildData.push_back(BVHPrimitiveInfo(i, bbox));
    }

    // Recursively build BVH tree for primitives
    MemoryArena buildArena;
    uint32_t totalNodes = 0;
    vector<Reference<Primitive> > orderedPrims;
    orderedPrims.reserve(primitives.size());
    BVHBuildNode *root = recursiveBuild(buildArena, buildData, 0,
                                        primitives.size(), &totalNodes,
                                        orderedPrims);
    primitives.swap(orderedPrims);
        Info("BVH created with %d nodes for %d primitives (%.2f MB)", totalNodes,
             (int)primitives.size(), float(totalNodes * sizeof(LinearBVHNode))/(1024.f*1024.f));

    // Compute representation of depth-first traversal of BVH tree
    nodes = AllocAligned<LinearBVHNode>(totalNodes);
    for (uint32_t i = 0; i < totalNodes; ++i)
        new (&nodes[i]) LinearBVHNode;
    uint32_t offset = 0;
    flattenBVHTree(root, &offset);
    Assert(offset == totalNodes);
    PBRT_BVH_FINISHED_CONSTRUCTION(this);
	
	//printf("done creating bvh with %d nodes for %d primitives\n", totalNodes, (int)primitives.size());
}
Ejemplo n.º 11
0
	void AssimpAssetLoader::recursiveBuild(const aiNode *node, aiMatrix4x4 worldSpace)
	{
		if(node == NULL)
			return;

		processNode(node, worldSpace);

		// iterate child nodes
		aiMatrix4x4 worldNodeTransform = worldSpace * node->mTransformation;
		for (int i = 0; i < node->mNumChildren; i++)
		{
			aiNode *child = node->mChildren[i];
			recursiveBuild(child, worldNodeTransform);
		}
	}
Ejemplo n.º 12
0
BAH::BAH(Mesh2D *m) {
  mesh.reset(m);
  std::vector<BAHElement> buildData;
  for (size_t i = 0; i < mesh->getMesh()->meshDescriptor.count; i++)
    buildData.emplace_back(BAHElement(i, mesh->getMesh()->elementBBox(i)));
  uint32_t totalNodes = 0;
  orderedElements.reserve(mesh->getMesh()->meshDescriptor.count);
  root = recursiveBuild(buildData, 0, mesh->getMesh()->meshDescriptor.count,
                        &totalNodes, orderedElements);
  nodes.resize(totalNodes);
  for (uint32_t i = 0; i < totalNodes; i++)
    new (&nodes[i]) LinearBAHNode;
  uint32_t offset = 0;
  flattenBAHTree(root, &offset);
}
Ejemplo n.º 13
0
    void build(size_t count, PositionFunctor getPosition, IsValidFunctor isValid) {
        clear();

        // Extract valid indices
        std::vector<uint32_t> indices;
        indices.reserve(count);
        for(uint32_t i = 0; i < count; ++i) {
            if(isValid(i)) {
                indices.push_back(i);
            }
        }

        m_Nodes.resize(indices.size());
        m_NodesData.resize(indices.size());
        uint32_t nextFreeNode = 1;

        recursiveBuild(0, 0, indices.size(), indices.data(), getPosition, nextFreeNode);
    }
Ejemplo n.º 14
0
void BvhBuilder::build(PrimVector prims)
{
    if (prims.empty())
        return;
    Box3fp geomBounds, centroidBounds;
    for (const Primitive &p : prims) {
        geomBounds.grow(p.box());
        centroidBounds.grow(p.centroid());
    }

    BuildResult result;
    recursiveBuild(result, *_root, 0, uint32(prims.size() - 1), prims, narrow(geomBounds), narrow(centroidBounds), _branchFactor);
    _numNodes = result.nodeCount;
    _depth = result.depth;

#ifndef NDEBUG
    integrityCheck(*_root, 0);
#endif
}
Ejemplo n.º 15
0
	AssetLoader::meshptr_type AssimpAssetLoader::buildMesh(const aiNode &node)
	{
		mCurrentMesh = createMeshImpl(node.mName.C_Str());

		aiVector3D pos, scl;
 		aiQuaternion rot;
 		aiMatrix4x4 worldSpace;
		worldSpace.Decompose(scl, rot, pos);
		glm::vec3 position(pos.x, pos.y, pos.z);
		glm::quat rotation(rot.w, rot.x, rot.y, rot.z);
		glm::vec3 scale(scl.x, scl.y, scl.z);
		setTransformImpl(mCurrentMesh, position, rotation, scale);
		//logNodes(node, 0);

		//mCurrentSkeleton = createSkeleton(node);

		recursiveBuild(&node, worldSpace);

		return mCurrentMesh;
	}
Ejemplo n.º 16
0
// BVHAccel Method Definitions
BVHAccel::BVHAccel(const std::vector<std::shared_ptr<Primitive>> &p,
                   int maxPrimsInNode, SplitMethod splitMethod)
    : maxPrimsInNode(std::min(255, maxPrimsInNode)),
      primitives(p),
      splitMethod(splitMethod) {
    StatTimer buildTime(&constructionTime);
    if (primitives.size() == 0) return;
    // Build BVH from _primitives_

    // Initialize _primitiveInfo_ array for primitives
    std::vector<BVHPrimitiveInfo> primitiveInfo(primitives.size());
    for (size_t i = 0; i < primitives.size(); ++i)
        primitiveInfo[i] = {i, primitives[i]->WorldBound()};

    // Build BVH tree for primitives using _primitiveInfo_
    MemoryArena arena(1024 * 1024);
    int totalNodes = 0;
    std::vector<std::shared_ptr<Primitive>> orderedPrims;
    orderedPrims.reserve(primitives.size());
    BVHBuildNode *root;
    if (splitMethod == SplitMethod::HLBVH)
        root = HLBVHBuild(arena, primitiveInfo, &totalNodes, orderedPrims);
    else
        root = recursiveBuild(arena, primitiveInfo, 0, primitives.size(),
                              &totalNodes, orderedPrims);
    primitives.swap(orderedPrims);
    Info("BVH created with %d nodes for %d primitives (%.2f MB)", totalNodes,
         (int)primitives.size(),
         float(totalNodes * sizeof(LinearBVHNode)) / (1024.f * 1024.f));

    // Compute representation of depth-first traversal of BVH tree
    treeBytes += totalNodes * sizeof(LinearBVHNode) + sizeof(*this) +
                 primitives.size() * sizeof(primitives[0]);
    nodes = AllocAligned<LinearBVHNode>(totalNodes);
    int offset = 0;
    flattenBVHTree(root, &offset);
    Assert(offset == totalNodes);
}
Ejemplo n.º 17
0
void BVH::build(std::vector<Triangle *> triangles, std::vector<Instance *> *instances)
{
    std::cout << "Building BVH" << std::endl;
	m_buildData.reserve(triangles.size());
	m_triangles = triangles;
	for(int i=0;i<triangles.size();i++){
		m_buildData.push_back(BVHTriangleInfo(i,AABoundingBox(triangles[i]), 0, 1 ));
	}
    if(instances != 0){
        m_instances = *instances;
        for(int i=0;i<instances->size();i++){
            m_buildData.push_back(BVHTriangleInfo(i,(*instances)[i]->m_bounds, 1, (*instances)[i]->getNumTris()));
        }
    }
    int numTotalNodes = 0;
	BVHBuildNode *buildRoot = recursiveBuild(0,m_buildData.size(),&numTotalNodes);
    m_root = new BVHLinearNode[numTotalNodes];
    int offset = 0;
    flattenTree(buildRoot,&offset);
    recursiveDelete(buildRoot);
    m_buildData.clear();
    writeObjFile("/tmp/bvh.obj");
}
Ejemplo n.º 18
0
bool	SOctree::build(GeomDB & geometry, sBuildInfo & bi)
{
	// Find the bounding box of the entire scene

	RadPrimList &	inPolys = geometry.polys();
	geom::Point3	min = inPolys.head()->data().xyz()[0];
	geom::Point3	max = inPolys.head()->data().xyz()[0];
	float		totalArea = 0;

	//if (bi.progressDialog) bi.progressDialog->setCurrentStatus("Preparing scene...");

	// Get the bounding box of the scene from polygons
	{
		RadPrimList::node *	n = inPolys.head();
		unsigned int	index = 0;
		while(n)
		{
			//if (!(index&0xf) && bi.progressDialog) bi.progressDialog->setCurrentPercent(static_cast<float>(index) / static_cast<float>(inPolys.size()) * 100.0f);
			index++;

			const RadPrim &	p = n->data();
			for (unsigned int j = 0; j < p.xyz().size(); ++j)
			{
				min.x() = fstl::min(min.x(), p.xyz()[j].x());
				min.y() = fstl::min(min.y(), p.xyz()[j].y());
				min.z() = fstl::min(min.z(), p.xyz()[j].z());

				max.x() = fstl::max(max.x(), p.xyz()[j].x());
				max.y() = fstl::max(max.y(), p.xyz()[j].y());
				max.z() = fstl::max(max.z(), p.xyz()[j].z());
			}

			// Calculate surface area for tracking percent complete

			totalArea += p.calcArea();

			n = n->next();
		}
	}

	// Account for lights in the bounding box

	const	RadPatchList &	inLights = geometry.lights();
	{
		for (RadPatchList::node * i = inLights.head(); i; i = i->next())
		{
			const RadPatch &	l = i->data();
			min.x() = fstl::min(min.x(), l.origin().x());
			min.y() = fstl::min(min.y(), l.origin().y());
			min.z() = fstl::min(min.z(), l.origin().z());
			max.x() = fstl::max(max.x(), l.origin().x());
			max.y() = fstl::max(max.y(), l.origin().y());
			max.z() = fstl::max(max.z(), l.origin().z());
		}
	}

	// Generate a new buildinfo struct with the statistics initialized

	bi.maxDepth = 0;
	bi.totalDepth = 0;
	bi.originalPolys = inPolys.size();
	bi.totalPolys = 0;
	bi.totalLights = 0;
	bi.totalLightmaps = geometry.lightmaps().size();
	bi.totalNodes = 0;
	bi.totalSceneSurfaceArea = totalArea;
	bi.processedSurfaceArea = 0;

	// Initial polygon count

	char	dsp[90];
	sprintf(dsp, "%d", bi.originalPolys);
	//if (bi.progressDialog)
	//{
	//	bi.progressDialog->setLabel1("Polygons:");
	//	bi.progressDialog->setText1(dsp);
	//	bi.progressDialog->setCurrentPercent(0.0f);
	//	bi.progressDialog->setCurrentStatus("Building splitting octree...");
	//}

	// Root's center & radius...

	geom::Point3	boxDim = max - min;
	center() = min + boxDim / 2;
	radius() = fstl::max(boxDim.x(), fstl::max(boxDim.y(), boxDim.z())) / 2;

	// Start the recursive build process

	if (!recursiveBuild(inPolys, inLights, bi)) return false;

	// Force an update for that "100%" status

	updateDisplay(bi, 0, true);

	return true;
}
Ejemplo n.º 19
0
BVHBuildNode *BVHAccel::recursiveBuild(MemoryArena &buildArena,
        vector<BVHPrimitiveInfo> &buildData, uint32_t start,
        uint32_t end, uint32_t *totalNodes,
        vector<Reference<Primitive> > &orderedPrims) {
    Assert(start != end);
    (*totalNodes)++;
    BVHBuildNode *node = buildArena.Alloc<BVHBuildNode>();
    // Compute bounds of all primitives in BVH node
    BBox bbox;
    for (uint32_t i = start; i < end; ++i)
        bbox = Union(bbox, buildData[i].bounds);
    uint32_t nPrimitives = end - start;
    if (nPrimitives == 1) {
        // Create leaf _BVHBuildNode_
        uint32_t firstPrimOffset = orderedPrims.size();
        for (uint32_t i = start; i < end; ++i) {
            uint32_t primNum = buildData[i].primitiveNumber;
            orderedPrims.push_back(primitives[primNum]);
        }
        node->InitLeaf(firstPrimOffset, nPrimitives, bbox);
    }
    else {
        // Compute bound of primitive centroids, choose split dimension _dim_
        BBox centroidBounds;
        for (uint32_t i = start; i < end; ++i)
            centroidBounds = Union(centroidBounds, buildData[i].centroid);
        int dim = centroidBounds.MaximumExtent();

        // Partition primitives into two sets and build children
        uint32_t mid = (start + end) / 2;
        if (centroidBounds.pMax[dim] == centroidBounds.pMin[dim]) {
            // Create leaf _BVHBuildNode_
            uint32_t firstPrimOffset = orderedPrims.size();
            for (uint32_t i = start; i < end; ++i) {
                uint32_t primNum = buildData[i].primitiveNumber;
                orderedPrims.push_back(primitives[primNum]);
            }
            node->InitLeaf(firstPrimOffset, nPrimitives, bbox);
            return node;
        }

        // Partition primitives based on _splitMethod_
        switch (splitMethod) {
        case SPLIT_MIDDLE: {
            // Partition primitives through node's midpoint
            float pmid = .5f * (centroidBounds.pMin[dim] + centroidBounds.pMax[dim]);
            BVHPrimitiveInfo *midPtr = std::partition(&buildData[start],
                                                      &buildData[end-1]+1,
                                                      CompareToMid(dim, pmid));
            mid = midPtr - &buildData[0];
            if (mid != start && mid != end)
                // for lots of prims with large overlapping bounding boxes, this
                // may fail to partition; in that case don't break and fall through
                // to SPLIT_EQUAL_COUNTS
                break;
        }
        case SPLIT_EQUAL_COUNTS: {
            // Partition primitives into equally-sized subsets
            mid = (start + end) / 2;
            std::nth_element(&buildData[start], &buildData[mid],
                             &buildData[end-1]+1, ComparePoints(dim));
            break;
        }
        case SPLIT_SAH: default: {
            // Partition primitives using approximate SAH
            if (nPrimitives <= 4) {
                // Partition primitives into equally-sized subsets
                mid = (start + end) / 2;
                std::nth_element(&buildData[start], &buildData[mid],
                                 &buildData[end-1]+1, ComparePoints(dim));
            }
            else {
                // Allocate _BucketInfo_ for SAH partition buckets
                const int nBuckets = 12;
                struct BucketInfo {
                    BucketInfo() { count = 0; }
                    int count;
                    BBox bounds;
                };
                BucketInfo buckets[nBuckets];

                // Initialize _BucketInfo_ for SAH partition buckets
                for (uint32_t i = start; i < end; ++i) {
                    int b = nBuckets *
                        ((buildData[i].centroid[dim] - centroidBounds.pMin[dim]) /
                         (centroidBounds.pMax[dim] - centroidBounds.pMin[dim]));
                    if (b == nBuckets) b = nBuckets-1;
                    Assert(b >= 0 && b < nBuckets);
                    buckets[b].count++;
                    buckets[b].bounds = Union(buckets[b].bounds, buildData[i].bounds);
                }

                // Compute costs for splitting after each bucket
                float cost[nBuckets-1];
                for (int i = 0; i < nBuckets-1; ++i) {
                    BBox b0, b1;
                    int count0 = 0, count1 = 0;
                    for (int j = 0; j <= i; ++j) {
                        b0 = Union(b0, buckets[j].bounds);
                        count0 += buckets[j].count;
                    }
                    for (int j = i+1; j < nBuckets; ++j) {
                        b1 = Union(b1, buckets[j].bounds);
                        count1 += buckets[j].count;
                    }
                    cost[i] = .125f + (count0*b0.SurfaceArea() + count1*b1.SurfaceArea()) /
                              bbox.SurfaceArea();
                }

                // Find bucket to split at that minimizes SAH metric
                float minCost = cost[0];
                uint32_t minCostSplit = 0;
                for (int i = 1; i < nBuckets-1; ++i) {
                    if (cost[i] < minCost) {
                        minCost = cost[i];
                        minCostSplit = i;
                    }
                }

                // Either create leaf or split primitives at selected SAH bucket
                if (nPrimitives > maxPrimsInNode ||
                    minCost < nPrimitives) {
                    BVHPrimitiveInfo *pmid = std::partition(&buildData[start],
                        &buildData[end-1]+1,
                        CompareToBucket(minCostSplit, nBuckets, dim, centroidBounds));
                    mid = pmid - &buildData[0];
                }
                
                else {
                    // Create leaf _BVHBuildNode_
                    uint32_t firstPrimOffset = orderedPrims.size();
                    for (uint32_t i = start; i < end; ++i) {
                        uint32_t primNum = buildData[i].primitiveNumber;
                        orderedPrims.push_back(primitives[primNum]);
                    }
                    node->InitLeaf(firstPrimOffset, nPrimitives, bbox);
                    return node;
                }
            }
            break;
        }
        }
        node->InitInterior(dim,
                           recursiveBuild(buildArena, buildData, start, mid,
                                          totalNodes, orderedPrims),
                           recursiveBuild(buildArena, buildData, mid, end,
                                          totalNodes, orderedPrims));
    }
    return node;
}
Ejemplo n.º 20
0
// Construye la tabla de compresión asociada al árbol de Huffman.
ZipTable buildTable(HuffmanTree t) {
    ZipTable zt = emptyZipTable();
    BitChain bc = emptyBitChain();

    return recursiveBuild(zt, t, bc);
}
Ejemplo n.º 21
0
static
KDNode *
recursiveBuild(const GeDynamicArray<Vector> &points, const Int32 *pnts, Int32 numPoints, Random &rng, INT depth, Sorter &sorter)
{
	KDNode *node =NewMemClear(KDNode,1);
	Int32 minNodeEntries = 4;
	Int32 maxDepth = 10;
	if(numPoints > minNodeEntries && depth < maxDepth){
		INT axis = depth%3;
		Float splitPos = getMedian(points,pnts,numPoints,rng,axis,sorter);
		Int32 numLeft = 0;
		for(Int32 i=0;i<numPoints;i++){
			switch(axis){
				case 0:
					if(points[pnts[i]].x < splitPos){
						numLeft++;
					}
					break;
				case 1:
					if(points[pnts[i]].y < splitPos){
						numLeft++;
					}
					break;
				case 2:
					if(points[pnts[i]].z < splitPos){
						numLeft++;
					}
					break;
			}
			
		}
		Int32 *lPoints = NewMemClear(Int32,numLeft);
		Int32 *rPoints = NewMemClear(Int32,numPoints - numLeft);
		Int32 lPos=0;
		Int32 rPos=0;
		for(Int32 i=0;i<numPoints;i++){
			Float val = 0;
			switch(axis){
				case 0:
					val = points[pnts[i]].x;
					break;
				case 1:
					val = points[pnts[i]].y;
					break;
				case 2:
					val = points[pnts[i]].z;
					break;
			}
			if(val < splitPos){
				lPoints[lPos] = pnts[i];
				lPos++;
			}
			else{
				rPoints[rPos] = pnts[i];
				rPos++;
			}
		}
		node->initInterior(splitPos);
		node->m_lChild = recursiveBuild(points,lPoints,numLeft,rng,depth+1,sorter);
		node->m_rChild = recursiveBuild(points,rPoints,numPoints-numLeft,rng,depth+1,sorter);
		DeleteMem(pnts);
	}
	else{
		node->initLeaf(pnts,numPoints);
	}
	return node;
}
Ejemplo n.º 22
0
 void KDTree::init(std::vector<KDTreeNodeRef> &objectList, AABB &aabb) {
     this->objectList = objectList;
     this->aabb = aabb;
     this->rootNode = recursiveBuild(objectList, aabb, 0);
 }
Ejemplo n.º 23
0
CBVH_PBRT::CBVH_PBRT( const CGENERICCONTAINER &aObjectContainer,
                      int aMaxPrimsInNode,
                      SPLITMETHOD aSplitMethod ) :
    m_maxPrimsInNode( std::min( 255, aMaxPrimsInNode ) ),
    m_splitMethod( aSplitMethod )
{
    if( aObjectContainer.GetList().empty() )
    {
        m_nodes = NULL;

        return;
    }

    // Initialize the indexes of ray packet for partition traversal
    for( unsigned int i = 0; i < RAYPACKET_RAYS_PER_PACKET; ++i )
    {
        m_I[i] = i;
    }

    // Convert the objects list to vector of objects
    // /////////////////////////////////////////////////////////////////////////
    aObjectContainer.ConvertTo( m_primitives );

    wxASSERT( aObjectContainer.GetList().size() == m_primitives.size() );

    // Initialize _primitiveInfo_ array for primitives
    // /////////////////////////////////////////////////////////////////////////
    std::vector<BVHPrimitiveInfo> primitiveInfo( m_primitives.size() );

    for( size_t i = 0; i < m_primitives.size(); ++i )
    {
        wxASSERT( m_primitives[i]->GetBBox().IsInitialized() );

        primitiveInfo[i] = BVHPrimitiveInfo( i, m_primitives[i]->GetBBox() );
    }

    // Build BVH tree for primitives using _primitiveInfo_
    int totalNodes = 0;

    CONST_VECTOR_OBJECT orderedPrims;
    orderedPrims.clear();
    orderedPrims.reserve( m_primitives.size() );

    BVHBuildNode *root;

    if( m_splitMethod == SPLIT_HLBVH )
        root = HLBVHBuild( primitiveInfo, &totalNodes, orderedPrims);
    else
        root = recursiveBuild( primitiveInfo, 0, m_primitives.size(),
                               &totalNodes, orderedPrims);

    wxASSERT( m_primitives.size() == orderedPrims.size() );

    m_primitives.swap( orderedPrims );

    // Compute representation of depth-first traversal of BVH tree
    m_nodes = static_cast<LinearBVHNode *>( _mm_malloc( sizeof( LinearBVHNode ) *
                                                        totalNodes,
                                                        L1_CACHE_LINE_SIZE ) );
    m_addresses_pointer_to_mm_free.push_back( m_nodes );

    for( int i = 0; i < totalNodes; ++i )
    {
        m_nodes[i].bounds.Reset();
        m_nodes[i].primitivesOffset = 0;
        m_nodes[i].nPrimitives = 0;
        m_nodes[i].axis = 0;
    }

    uint32_t offset = 0;

    flattenBVHTree( root, &offset );

    wxASSERT( offset == (unsigned int)totalNodes );

#ifdef PRINT_STATISTICS_3D_VIEWER
    uint32_t treeBytes = totalNodes * sizeof( LinearBVHNode ) + sizeof( *this ) +
                         m_primitives.size() * sizeof( m_primitives[0] ) +
                         m_addresses_pointer_to_mm_free.size() * sizeof( void * );

    printf( "////////////////////////////////////////////////////////////////////////////////\n" );
    printf( "Creating a CBVH_PBRT from %u objects ", (unsigned int)m_primitives.size() );

    switch( m_splitMethod )
    {
    case SPLIT_MIDDLE:      printf( "using SPLIT_MIDDLE\n" ); break;
    case SPLIT_EQUALCOUNTS: printf( "using SPLIT_EQUALCOUNTS\n" ); break;
    case SPLIT_SAH:         printf( "using SPLIT_SAH\n" ); break;
    case SPLIT_HLBVH:       printf( "using SPLIT_HLBVH\n" ); break;
    }

    printf( "  BVH created with %d nodes (%.2f MB)\n",
            totalNodes, float(treeBytes) / (1024.f * 1024.f) );
    printf( "////////////////////////////////////////////////////////////////////////////////\n\n" );
#endif
}
Ejemplo n.º 24
0
BVHBuildNode *CBVH_PBRT::recursiveBuild ( std::vector<BVHPrimitiveInfo> &primitiveInfo,
                                          int start,
                                          int end,
                                          int *totalNodes,
                                          CONST_VECTOR_OBJECT &orderedPrims )
{
    wxASSERT( totalNodes != NULL );
    wxASSERT( start >= 0 );
    wxASSERT( end   >= 0 );
    wxASSERT( start != end );
    wxASSERT( start < end );
    wxASSERT( start <= (int)primitiveInfo.size() );
    wxASSERT( end   <= (int)primitiveInfo.size() );

    (*totalNodes)++;

    // !TODO: implement an memory Arena
    BVHBuildNode *node = static_cast<BVHBuildNode *>( _mm_malloc( sizeof( BVHBuildNode ),
                                                                  L1_CACHE_LINE_SIZE ) );
    m_addresses_pointer_to_mm_free.push_back( node );

    node->bounds.Reset();
    node->firstPrimOffset = 0;
    node->nPrimitives = 0;
    node->splitAxis = 0;
    node->children[0] = NULL;
    node->children[1] = NULL;

    // Compute bounds of all primitives in BVH node
    CBBOX bounds;
    bounds.Reset();

    for( int i = start; i < end; ++i )
        bounds.Union( primitiveInfo[i].bounds );

    int nPrimitives = end - start;

    if( nPrimitives == 1 )
    {
        // Create leaf _BVHBuildNode_
        int firstPrimOffset = orderedPrims.size();

        for( int i = start; i < end; ++i )
        {
            int primitiveNr = primitiveInfo[i].primitiveNumber;
            wxASSERT( primitiveNr < (int)m_primitives.size() );
            orderedPrims.push_back( m_primitives[ primitiveNr ] );
        }

        node->InitLeaf( firstPrimOffset, nPrimitives, bounds );
    }
    else
    {
        // Compute bound of primitive centroids, choose split dimension _dim_
        CBBOX centroidBounds;
        centroidBounds.Reset();

        for( int i = start; i < end; ++i )
            centroidBounds.Union( primitiveInfo[i].centroid );

        const int dim = centroidBounds.MaxDimension();

        // Partition primitives into two sets and build children
        int mid = (start + end) / 2;

        if( fabs( centroidBounds.Max()[dim] -
                  centroidBounds.Min()[dim] ) < (FLT_EPSILON + FLT_EPSILON) )
        {
            // Create leaf _BVHBuildNode_
            const int firstPrimOffset = orderedPrims.size();

            for( int i = start; i < end; ++i )
            {
                int primitiveNr = primitiveInfo[i].primitiveNumber;

                wxASSERT( (primitiveNr >= 0) &&
                          (primitiveNr < (int)m_primitives.size()) );

                const COBJECT *obj = static_cast<const COBJECT *>( m_primitives[ primitiveNr ] );

                wxASSERT( obj != NULL );

                orderedPrims.push_back( obj );
            }

            node->InitLeaf( firstPrimOffset, nPrimitives, bounds );
        }
        else
        {
            // Partition primitives based on _splitMethod_
            switch( m_splitMethod )
            {
            case SPLIT_MIDDLE:
            {
                // Partition primitives through node's midpoint
                float pmid = centroidBounds.GetCenter( dim );

                BVHPrimitiveInfo *midPtr = std::partition( &primitiveInfo[start],
                                                           &primitiveInfo[end - 1] + 1,
                                                           CompareToMid( dim, pmid ) );
                mid = midPtr - &primitiveInfo[0];

                wxASSERT( (mid >= start) &&
                          (mid <= end) );

                if( (mid != start) && (mid != end) )
                    // for lots of prims with large overlapping bounding boxes, this
                    // may fail to partition; in that case don't break and fall through
                    // to SPLIT_EQUAL_COUNTS
                    break;
            }

            case SPLIT_EQUALCOUNTS:
            {
                // Partition primitives into equally-sized subsets
                mid = (start + end) / 2;

                std::nth_element( &primitiveInfo[start],
                                  &primitiveInfo[mid],
                                  &primitiveInfo[end - 1] + 1,
                                  ComparePoints( dim ) );

                break;
            }

            case SPLIT_SAH:
            default:
            {
                // Partition primitives using approximate SAH
                if( nPrimitives <= 2 )
                {
                    // Partition primitives into equally-sized subsets
                    mid = (start + end) / 2;

                    std::nth_element( &primitiveInfo[start],
                                      &primitiveInfo[mid],
                                      &primitiveInfo[end - 1] + 1,
                                      ComparePoints( dim ) );
                }
                else
                {
                    // Allocate _BucketInfo_ for SAH partition buckets
                    const int nBuckets = 12;

                    BucketInfo buckets[nBuckets];

                    for( int i = 0; i < nBuckets; ++i )
                    {
                        buckets[i].count = 0;
                        buckets[i].bounds.Reset();
                    }

                    // Initialize _BucketInfo_ for SAH partition buckets
                    for( int i = start; i < end; ++i )
                    {
                        int b = nBuckets *
                                centroidBounds.Offset( primitiveInfo[i].centroid )[dim];

                        if( b == nBuckets )
                            b = nBuckets - 1;

                        wxASSERT( b >= 0 && b < nBuckets );

                        buckets[b].count++;
                        buckets[b].bounds.Union( primitiveInfo[i].bounds );
                    }

                    // Compute costs for splitting after each bucket
                    float cost[nBuckets - 1];

                    for( int i = 0; i < (nBuckets - 1); ++i )
                    {
                        CBBOX b0, b1;

                        b0.Reset();
                        b1.Reset();

                        int count0 = 0;
                        int count1 = 0;

                        for( int j = 0; j <= i; ++j )
                        {
                            if( buckets[j].count )
                            {
                                count0 += buckets[j].count;
                                b0.Union( buckets[j].bounds );
                            }
                        }

                        for( int j = i + 1; j < nBuckets; ++j )
                        {
                            if( buckets[j].count )
                            {
                                count1 += buckets[j].count;
                                b1.Union( buckets[j].bounds );
                            }
                        }

                        cost[i] = 1.0f +
                                  ( count0 * b0.SurfaceArea() +
                                    count1 * b1.SurfaceArea() ) /
                                  bounds.SurfaceArea();
                    }

                    // Find bucket to split at that minimizes SAH metric
                    float minCost = cost[0];
                    int minCostSplitBucket = 0;

                    for( int i = 1; i < (nBuckets - 1); ++i )
                    {
                        if( cost[i] < minCost )
                        {
                            minCost = cost[i];
                            minCostSplitBucket = i;
                        }
                    }

                    // Either create leaf or split primitives at selected SAH
                    // bucket
                    if( (nPrimitives > m_maxPrimsInNode) ||
                        (minCost < (float)nPrimitives) )
                    {
                        BVHPrimitiveInfo *pmid =
                            std::partition( &primitiveInfo[start],
                                            &primitiveInfo[end - 1] + 1,
                                            CompareToBucket( minCostSplitBucket,
                                                             nBuckets,
                                                             dim,
                                                             centroidBounds ) );
                        mid = pmid - &primitiveInfo[0];

                        wxASSERT( (mid >= start) &&
                                  (mid <= end) );
                    }
                    else
                    {
                        // Create leaf _BVHBuildNode_
                        const int firstPrimOffset = orderedPrims.size();

                        for( int i = start; i < end; ++i )
                        {
                            const int primitiveNr = primitiveInfo[i].primitiveNumber;

                            wxASSERT( primitiveNr < (int)m_primitives.size() );

                            orderedPrims.push_back( m_primitives[ primitiveNr ] );
                        }

                        node->InitLeaf( firstPrimOffset, nPrimitives, bounds );

                        return node;
                    }
                }
                break;
            }
            }

            node->InitInterior( dim,
                                recursiveBuild( primitiveInfo,
                                                start,
                                                mid,
                                                totalNodes,
                                                orderedPrims ),
                                recursiveBuild( primitiveInfo,
                                                mid,
                                                end,
                                                totalNodes,
                                                orderedPrims) );
        }
    }

    return node;
}
Ejemplo n.º 25
0
BVHBuildNode *BVHAccel::recursiveBuild(
    MemoryArena &arena, std::vector<BVHPrimitiveInfo> &primitiveInfo, int start,
    int end, int *totalNodes,
    std::vector<std::shared_ptr<Primitive>> &orderedPrims) {
    Assert(start != end);
    BVHBuildNode *node = arena.Alloc<BVHBuildNode>();
    (*totalNodes)++;
    // Compute bounds of all primitives in BVH node
    Bounds3f bounds;
    for (int i = start; i < end; ++i)
        bounds = Union(bounds, primitiveInfo[i].bounds);
    int nPrimitives = end - start;
    if (nPrimitives == 1) {
        // Create leaf _BVHBuildNode_
        int firstPrimOffset = orderedPrims.size();
        for (int i = start; i < end; ++i) {
            int primNum = primitiveInfo[i].primitiveNumber;
            orderedPrims.push_back(primitives[primNum]);
        }
        node->InitLeaf(firstPrimOffset, nPrimitives, bounds);
    } else {
        // Compute bound of primitive centroids, choose split dimension _dim_
        Bounds3f centroidBounds;
        for (int i = start; i < end; ++i)
            centroidBounds = Union(centroidBounds, primitiveInfo[i].centroid);
        int dim = centroidBounds.MaximumExtent();

        // Partition primitives into two sets and build children
        int mid = (start + end) / 2;
        if (centroidBounds.pMax[dim] == centroidBounds.pMin[dim]) {
            // Create leaf _BVHBuildNode_
            int firstPrimOffset = orderedPrims.size();
            for (int i = start; i < end; ++i) {
                int primNum = primitiveInfo[i].primitiveNumber;
                orderedPrims.push_back(primitives[primNum]);
            }
            node->InitLeaf(firstPrimOffset, nPrimitives, bounds);
        } else {
            // Partition primitives based on _splitMethod_
            switch (splitMethod) {
            case SplitMethod::Middle: {
                // Partition primitives through node's midpoint
                Float pmid =
                    (centroidBounds.pMin[dim] + centroidBounds.pMax[dim]) / 2;
                BVHPrimitiveInfo *midPtr = std::partition(
                    &primitiveInfo[start], &primitiveInfo[end - 1] + 1,
                    [dim, pmid](const BVHPrimitiveInfo &pi) {
                        return pi.centroid[dim] < pmid;
                    });
                mid = midPtr - &primitiveInfo[0];
                // For lots of prims with large overlapping bounding boxes, this
                // may fail to partition; in that case don't break and fall
                // through
                // to EqualCounts.
                if (mid != start && mid != end) break;
            }
            case SplitMethod::EqualCounts: {
                // Partition primitives into equally-sized subsets
                mid = (start + end) / 2;
                std::nth_element(&primitiveInfo[start], &primitiveInfo[mid],
                                 &primitiveInfo[end - 1] + 1,
                                 [dim](const BVHPrimitiveInfo &a,
                                       const BVHPrimitiveInfo &b) {
                                     return a.centroid[dim] < b.centroid[dim];
                                 });
                break;
            }
            case SplitMethod::SAH:
            default: {
                // Partition primitives using approximate SAH
                if (nPrimitives <= 4) {
                    // Partition primitives into equally-sized subsets
                    mid = (start + end) / 2;
                    std::nth_element(&primitiveInfo[start], &primitiveInfo[mid],
                                     &primitiveInfo[end - 1] + 1,
                                     [dim](const BVHPrimitiveInfo &a,
                                           const BVHPrimitiveInfo &b) {
                                         return a.centroid[dim] <
                                                b.centroid[dim];
                                     });
                } else {
                    // Allocate _BucketInfo_ for SAH partition buckets
                    constexpr int nBuckets = 12;
                    struct BucketInfo {
                        int count = 0;
                        Bounds3f bounds;
                    };
                    BucketInfo buckets[nBuckets];

                    // Initialize _BucketInfo_ for SAH partition buckets
                    for (int i = start; i < end; ++i) {
                        int b = nBuckets *
                                centroidBounds.Offset(
                                    primitiveInfo[i].centroid)[dim];
                        if (b == nBuckets) b = nBuckets - 1;
                        Assert(b >= 0 && b < nBuckets);
                        buckets[b].count++;
                        buckets[b].bounds =
                            Union(buckets[b].bounds, primitiveInfo[i].bounds);
                    }

                    // Compute costs for splitting after each bucket
                    Float cost[nBuckets - 1];
                    for (int i = 0; i < nBuckets - 1; ++i) {
                        Bounds3f b0, b1;
                        int count0 = 0, count1 = 0;
                        for (int j = 0; j <= i; ++j) {
                            b0 = Union(b0, buckets[j].bounds);
                            count0 += buckets[j].count;
                        }
                        for (int j = i + 1; j < nBuckets; ++j) {
                            b1 = Union(b1, buckets[j].bounds);
                            count1 += buckets[j].count;
                        }
                        cost[i] = .125f +
                                  (count0 * b0.SurfaceArea() +
                                   count1 * b1.SurfaceArea()) /
                                      bounds.SurfaceArea();
                    }

                    // Find bucket to split at that minimizes SAH metric
                    Float minCost = cost[0];
                    int minCostSplitBucket = 0;
                    for (int i = 1; i < nBuckets - 1; ++i) {
                        if (cost[i] < minCost) {
                            minCost = cost[i];
                            minCostSplitBucket = i;
                        }
                    }

                    // Either create leaf or split primitives at selected SAH
                    // bucket
                    Float leafCost = nPrimitives;
                    if (nPrimitives > maxPrimsInNode || minCost < leafCost) {
                        BVHPrimitiveInfo *pmid = std::partition(
                            &primitiveInfo[start], &primitiveInfo[end - 1] + 1,
                            [=](const BVHPrimitiveInfo &pi) {
                                int b = nBuckets *
                                        centroidBounds.Offset(pi.centroid)[dim];
                                if (b == nBuckets) b = nBuckets - 1;
                                Assert(b >= 0 && b < nBuckets);
                                return b <= minCostSplitBucket;
                            });
                        mid = pmid - &primitiveInfo[0];
                    } else {
                        // Create leaf _BVHBuildNode_
                        int firstPrimOffset = orderedPrims.size();
                        for (int i = start; i < end; ++i) {
                            int primNum = primitiveInfo[i].primitiveNumber;
                            orderedPrims.push_back(primitives[primNum]);
                        }
                        node->InitLeaf(firstPrimOffset, nPrimitives, bounds);
                    }
                }
                break;
            }
            }
            node->InitInterior(dim,
                               recursiveBuild(arena, primitiveInfo, start, mid,
                                              totalNodes, orderedPrims),
                               recursiveBuild(arena, primitiveInfo, mid, end,
                                              totalNodes, orderedPrims));
        }
    }
    return node;
}