Ejemplo n.º 1
0
		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 );
			}
		}
Ejemplo n.º 2
0
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());
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
0
		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;
			}
		}
Ejemplo n.º 5
0
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;
    }
}
Ejemplo n.º 6
0
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);
}