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; }
static void recursiveBuild(BuildResult &result, NaiveBvhNode &dst, uint32 start, uint32 end, PrimVector &prims, const Box3f &geomBox, const Box3f ¢roidBox, 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); } } } }
//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; }
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); }
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); } }
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; }
/** *@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; }
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; }
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); }
// 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()); }
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); } }
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); }
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); }
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 }
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; }
// 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); }
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"); }
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; }
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; }
// 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); }
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; }
void KDTree::init(std::vector<KDTreeNodeRef> &objectList, AABB &aabb) { this->objectList = objectList; this->aabb = aabb; this->rootNode = recursiveBuild(objectList, aabb, 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 }
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; }
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; }