void ObstacleKDTree::buildTree( const std::vector< Obstacle * > obstacles ) { deleteTree(); _obstacles.assign( obstacles.begin(), obstacles.end() ); if ( _obstacles.size() > 0 ) { std::vector< Obstacle * > temp; temp.assign( _obstacles.begin(), _obstacles.end() ); _tree = buildTreeRecursive( temp ); } }
void BVH::buildAccelStructure(const std::vector<Shape*>& sceneData){ Assert(scene.empty()); //Get bounding boxes for each shape scene.reserve(sceneData.size()); //Reserve space ahead of time to avoid realloc's for(size_t i = 0; i < sceneData.size(); i++){ //Bound current primitive BoundingBox currBBox = sceneData[i]->worldSpaceBound(); //Add bbox and shape to list BVH::ShapeWBound curr(sceneData[i], currBBox); scene.push_back(curr); } //Build tree recursively in a top down manner root = buildTreeRecursive(0, scene.begin(), scene.end()); }
void KdTreeAccelerator::buildTree() { // compute bounds for kd-tree construction std::vector<BBox> primitiveBounds; primitiveBounds.reserve(m_primitives.size()); for(uint i = 0; i < m_primitives.size(); ++i) { Triangle& prim = m_primitives[i]; BBox b = prim.getBBox(); m_boundingBox = BBox::Union(m_boundingBox, b); primitiveBounds.push_back(b); } // allocate memory for construction BoundEdge* edges[3]; for(int i = 0; i < 3; ++i) edges[i] = new BoundEdge[2 * m_primitives.size()]; uint* prims0 = new uint[m_primitives.size()]; uint* prims1 = new uint[(m_maxDepth+1) * m_primitives.size()]; // initialize overlapping primitives (all at the beginning) uint* overlappingPrimitives = new uint[m_primitives.size()]; for(uint i = 0; i < m_primitives.size(); ++i) { overlappingPrimitives[i] = i; } // start to recursively build the tree buildTreeRecursive(0, m_boundingBox, primitiveBounds, overlappingPrimitives, (int)m_primitives.size(), m_maxDepth, edges, prims0, prims1, 0); // release allocated memory for(int i = 0; i < 3; ++i) delete [] edges[i]; delete [] prims0; delete [] prims1; }
ObstacleTreeNode* ObstacleKDTree::buildTreeRecursive( const std::vector<Obstacle*>& obstacles) { if ( obstacles.empty() ) { return 0x0; } else { ObstacleTreeNode* const node = new ObstacleTreeNode; size_t optimalSplit = 0; size_t minLeft = obstacles.size(); size_t minRight = obstacles.size(); for (size_t i = 0; i < obstacles.size(); ++i) { size_t leftSize = 0; size_t rightSize = 0; const Obstacle* const obstacleI = obstacles[i]; const Vector2 I0 = obstacleI->getP0(); const Vector2 I1 = obstacleI->getP1(); /* Compute optimal split node. */ for (size_t j = 0; j < obstacles.size(); ++j) { if (i == j) { continue; } const Obstacle* const obstacleJ = obstacles[j]; const Vector2 J0 = obstacleJ->getP0(); const Vector2 J1 = obstacleJ->getP1(); const float j1LeftOfI = leftOf( I0, I1, J0 ); const float j2LeftOfI = leftOf( I0, I1, J1 ); if (j1LeftOfI >= -EPS && j2LeftOfI >= -EPS) { ++leftSize; } else if (j1LeftOfI <= EPS && j2LeftOfI <= EPS ) { ++rightSize; } else { ++leftSize; ++rightSize; } if (std::make_pair(std::max(leftSize, rightSize), std::min(leftSize, rightSize)) >= std::make_pair(std::max(minLeft, minRight), std::min(minLeft, minRight))) { break; } } if (std::make_pair(std::max(leftSize, rightSize), std::min(leftSize, rightSize)) < std::make_pair(std::max(minLeft, minRight), std::min(minLeft, minRight))) { minLeft = leftSize; minRight = rightSize; optimalSplit = i; } } /* Build split node. */ std::vector<Obstacle*> leftObstacles(minLeft); std::vector<Obstacle*> rightObstacles(minRight); size_t leftCounter = 0; size_t rightCounter = 0; const size_t i = optimalSplit; const Obstacle* const obstacleI = obstacles[i]; const Vector2 I0 = obstacleI->getP0(); const Vector2 I1 = obstacleI->getP1(); for (size_t j = 0; j < obstacles.size(); ++j) { if (i == j) { continue; } Obstacle* const obstacleJ = obstacles[j]; const Vector2 J0 = obstacleJ->getP0(); const Vector2 J1 = obstacleJ->getP1(); const float j1LeftOfI = leftOf( I0, I1, J0 ); const float j2LeftOfI = leftOf( I0, I1, J1 ); if (j1LeftOfI >= -EPS && j2LeftOfI >= -EPS ) { leftObstacles[leftCounter++] = obstacles[j]; } else if (j1LeftOfI <= EPS && j2LeftOfI <= EPS ) { rightObstacles[rightCounter++] = obstacles[j]; } else { /* Split obstacle j. */ const float t = det( I1 - I0, J0 - I0 ) / det( I1 -I0, J0 - J1 ); const Vector2 splitpoint = J0 + t * ( J1 - J0 ); Obstacle* const newObstacle = new Obstacle(); newObstacle->_point = splitpoint; newObstacle->_prevObstacle = obstacleJ; newObstacle->_nextObstacle = obstacleJ->_nextObstacle; if ( newObstacle->_nextObstacle ) { obstacleJ->_nextObstacle = newObstacle; } newObstacle->_isConvex = true; newObstacle->_unitDir = obstacleJ->_unitDir; newObstacle->_length = abs( J1 - newObstacle->_point ); newObstacle->_id = _obstacles.size(); newObstacle->_class = obstacleJ->_class; _obstacles.push_back(newObstacle); obstacleJ->_nextObstacle = newObstacle; obstacleJ->_length = abs( J0 - newObstacle->_point ); if (j1LeftOfI > 0.0f) { leftObstacles[leftCounter++] = obstacleJ; rightObstacles[rightCounter++] = newObstacle; } else { rightObstacles[rightCounter++] = obstacleJ; leftObstacles[leftCounter++] = newObstacle; } } } node->_obstacle = obstacleI; node->_left = buildTreeRecursive(leftObstacles); node->_right = buildTreeRecursive(rightObstacles); return node; } }
BVH::BVHNode* BVH::buildTreeRecursive(int level, std::vector<BVH::ShapeWBound>::iterator startIncl, std::vector<BVH::ShapeWBound>::iterator endIncl ) { std::cout << "btr level: " << level << std::endl; //We need to bound the primitives in the range [startIncl, endIncl] //within the std::vector scene //if there are <= primsPerLeaf primitives in this range, then we create a leaf node const int numPrimsInRange = std::distance(startIncl, endIncl); std::cout << "\tnum prims = " << numPrimsInRange << std::endl; Assert(numPrimsInRange >= 0); const bool makingLeaf = numPrimsInRange <= primsPerLeaf; //Compute a bounding box for all the primitives in this node //Note that here I use "std::accumulate," which I think should be //called "std::fold" for the functional programming "fold" function //found in languages like ML BoundingBox bbox; if(numPrimsInRange != 0){ bbox = std::accumulate(startIncl, endIncl, bbox, BVH::unionBBoxes); } std::cout << "\tbounding box: " << bbox << std::endl; //If no primitives are in range that indicates an edge case in which all the //primitives are in the other subtree and we should just build a degenerate //bounding box and make it a leaf. std::vector<BVH::ShapeWBound>::iterator leftStart, rightStart, leftEnd, rightEnd; if(makingLeaf){ //Making a leaf node std::cout << "Making a leaf." << std::endl; //Construct leaf BVH::BVHNode* newLeaf = new BVH::BVHNode(bbox, true); //Add data to the leaf //the data is a list of integers, where each integer is an index into //the array of primitives newLeaf->prims = makePrimList(scene, startIncl, endIncl); std::cout << "Made a leaf." << std::endl; return newLeaf; }else{ //Making an internal node //Allocate new node BVH::BVHNode* newInternal = new BVH::BVHNode(bbox, false); //Split the node based on the chosen split strategy BoundingBox leftBBox, rightBBox; if(strat == BVH::SPLIT_SAH){ //SAH = "Surface area heuristic" Assert(false); return NULL;//TODO: Implement }else if(strat == BVH::SPLIT_CENTER){ //Split down the center //We need to choose an axis to split on: X,Y, or Z //we choose based on the level in the tree const size_t axis = level % 3; std::cout << "\taxis = " << axis << std::endl; BBoxCentroidSorter sorter(axis); //Find the item that would take the nth position in //the array in the event that it was sorted //Note that this is faster than the O(n log(n)) //from naive sorting std::vector<BVH::ShapeWBound>::iterator midIter; //TODO: What should miditer be before this call? midIter = startIncl + (numPrimsInRange/2); std::nth_element(startIncl, midIter, endIncl, sorter); std::cout << "\tcompleted the partition." << std::endl; //Compute bounding boxes for each subtree /* std::cout << "\tBEGIN TEST CALLS." << std::endl; BVH::ShapeWBound t1 = *startIncl; std::cout << "\tstart bbox = " << t1 << std::endl; BVH::ShapeWBound t2 = *midIter; std::cout << "\tmid bbox = " << t2 << std::endl; BVH::ShapeWBound t3 = *endIncl; std::cout << "\tend bbox = " << t3 << std::endl; std::cout << "\tEND TEST CALLS." << std::endl; */ BoundingBox leftBBox = std::accumulate(startIncl, midIter-1, BoundingBox(), BVH::unionBBoxes); std::cout << "\tleft subtree bbox = " << leftBBox << std::endl; BoundingBox rightBBox = std::accumulate(midIter , endIncl , BoundingBox(), BVH::unionBBoxes); std::cout << "\tright subtree bbox = " << rightBBox << std::endl; std::cout << "\tcomputed subtree bounding boxes." << std::endl; //Partition the resulting objects into "those in the left subtree" //and "those in the right subtree" BVH::InBBoxTester bboxCheck(leftBBox); std::vector<BVH::ShapeWBound>::iterator bound = std::partition(startIncl, endIncl, bboxCheck); //Make sure that each primitive is in one of the two bounding boxes //TODO: Do this, but only in debug mode }else{ //We did not consider some strategy! (Should never happen) Assert(false); return NULL; } //Partition the primitives into each node //Recursively create children std::cout << "\tabout to make 2 recursive calls." << std::endl; newInternal->setLeftChild ( buildTreeRecursive(level + 1, leftStart , leftEnd )); newInternal->setRightChild( buildTreeRecursive(level + 1, rightStart, rightEnd)); return newInternal; } }
void KdTreeAccelerator::initializeInteriorNode(int node, const BBox& nodeBounds, const std::vector<BBox>& primitiveBounds, uint* overlappingPrimitives, int numOverlappingPrimitives, int depth, BoundEdge* edges[3], uint* prims0, uint* prims1, int badRefines) { // Choose split axis and position for interior node int bestAxis = -1; int bestOffset = -1; float bestCost = INFINITY; float oldCost = m_intersectionCost * float(numOverlappingPrimitives); float totalSA = nodeBounds.getSurfaceArea(); float invTotalSA = 1.f / totalSA; glm::vec3 d = nodeBounds.getMax() - nodeBounds.getMin(); uint axis = nodeBounds.getAxisMaximumExtent(); int retries = 0; // label for jump to choose another split retrySplit: // Initialize edges for choosen axis for(int i = 0; i < numOverlappingPrimitives; ++i) { int primitive = overlappingPrimitives[i]; const BBox& bbox = primitiveBounds[primitive]; edges[axis][2 * i + 0] = BoundEdge(bbox.getMin()[axis], primitive, true); edges[axis][2 * i + 1] = BoundEdge(bbox.getMax()[axis], primitive, false); } std::sort(&edges[axis][0], &edges[axis][2*numOverlappingPrimitives]); // Compute cost of all splits for the choosen axis to find best int nBelow = 0; int nAbove = numOverlappingPrimitives; for(int i = 0; i < 2 * numOverlappingPrimitives; ++i) { if(edges[axis][i].m_type == BoundEdge::END) --nAbove; float split = edges[axis][i].m_t; if(split > nodeBounds.getMin()[axis] && split < nodeBounds.getMax()[axis]) { // compute cost of split at i-th edge uint oA0 = (axis + 1) % 3; // first other axis uint oA1 = (axis + 2) % 3; // second other axis float belowSA = 2 * (d[oA0] * d[oA1] + (split - nodeBounds.getMin()[axis]) * (d[oA0] + d[oA1])); float aboveSA = 2 * (d[oA0] * d[oA1] + (nodeBounds.getMax()[axis] - split) * (d[oA0] + d[oA1])); float pBelow = belowSA * invTotalSA; float pAbove = aboveSA * invTotalSA; float bonus = (nAbove==0 || nBelow==0) ? m_emptyBonus : 0.f; float cost = m_intersectionCost * (1.f - bonus) * (pBelow * nBelow + pAbove * nAbove) + m_traversalCost; // update best split if this split has lower costs if(cost < bestCost) { bestCost = cost; bestAxis = axis; bestOffset = i; } } if(edges[axis][i].m_type == BoundEdge::START) ++nBelow; } // try another axis of no good slit was found if(bestAxis == -1 && retries < 2) { ++retries; axis = (axis + 1) % 3; goto retrySplit; } // Create lead if no good splits were found if (bestCost > oldCost) ++badRefines; if ((bestCost > 4.f * oldCost && numOverlappingPrimitives < 16) || bestAxis == -1 || badRefines == 3) { m_nodes[node].initLeaf(overlappingPrimitives, numOverlappingPrimitives); return; } // Classify overlapping primitives with respect to split int n0 = 0, n1 = 0; for (int i = 0; i < bestOffset; ++i) { if (edges[bestAxis][i].m_type == BoundEdge::START) { prims0[n0++] = edges[bestAxis][i].m_primitive; } } for (int i = bestOffset+1; i < 2*numOverlappingPrimitives; ++i) { if (edges[bestAxis][i].m_type == BoundEdge::END) { prims1[n1++] = edges[bestAxis][i].m_primitive; } } // Recursively initialize child nodes float split = edges[bestAxis][bestOffset].m_t; glm::vec3 min = nodeBounds.getMax(); glm::vec3 max = nodeBounds.getMin(); min[bestAxis] = split; max[bestAxis] = split; BBox bounds0 = nodeBounds; BBox bounds1 = nodeBounds; bounds0.setMax(max); bounds1.setMin(min); buildTreeRecursive(node + 1, bounds0, primitiveBounds, prims0, n0, depth - 1, edges, prims0, prims1 + numOverlappingPrimitives, badRefines); uint aboveChild = m_nextFreeNode; m_nodes[node].initInterior(bestAxis, aboveChild, split); buildTreeRecursive(aboveChild, bounds1, primitiveBounds, prims1, n1, depth - 1, edges, prims0, prims1 + numOverlappingPrimitives, badRefines); }