Exemple #1
0
void KdTreeAccel::buildTree(KdAccelNode* node, const Bounds3f &bound, vector<int> &prims,
	int depth, BoundEdge* edges[3])
{
	node->bbox = bound;
	int np = prims.size();
	//If not enough primitives or reach max depth of a tree
	//Create a leaf node
	if (np <= maxPrims || depth == 0)
	{
		node->initLeaf(prims);
		return;
	}
	//Interior node parameters
	int bestAxis = -1, bestOffest = -1;//Split axis and split index*2
	Float bestCost = INFINITY;
	Float oldCost = np;
	Float totalSA = bound.surfaceArea();
	Float invTotalSA = 1.0 / totalSA;
	Vector3f bbDiag = bound.pMax - bound.pMin;

	//choose max extension axis of bounding box
	int axis = bound.maxExtent();//axis is the longest edge of bounding box
	int retries = 0;
RETRY_SPLIT:
	//
	//Calculate surface cost
	for (int i = 0; i < np; ++i)
	{
		int prmIdx = prims[i];
		const Bounds3f tmpBox = primitives[prmIdx]->ObjBound;
		edges[axis][i * 2] = BoundEdge(tmpBox.pMin[axis], prmIdx, true);
		edges[axis][i * 2 + 1] = BoundEdge(tmpBox.pMax[axis], prmIdx, false);
	}

	sort(&edges[axis][0], &edges[axis][2 * np]);
	int nBelow(0), nAbove(np);
	for (int i = 0; i < 2 * np; ++i)
	{
		if (edges[axis][i].type == BoundEdge::END)
		{
			--nAbove;
		}
		Float edget = edges[axis][i].t;

		//when t is in between the boundary
		if (edget > bound.pMin[axis] && edget < bound.pMax[axis])
		{
			//Compute cost for split at ith edge
			//get other two axes
			int axis0 = (axis + 1) % 3, axis1 = (axis + 2) % 3;
			Float belowSA = 2 * (bbDiag[axis0] * bbDiag[axis1] +
				(edget - bound.pMin[axis]) *
				(bbDiag[axis0] + bbDiag[axis1]));
			Float aboveSA = 2 * (bbDiag[axis0] * bbDiag[axis1] +
				(bound.pMax[axis] - edget) *
				(bbDiag[axis0] + bbDiag[axis1]));
			Float pBelow = belowSA * invTotalSA;
			Float pAbove = aboveSA * invTotalSA;
			Float eb = (nAbove == 0 || nBelow == 0) ? emptyBonus : 0;
			Float cost = (1.0 - eb) * (pBelow * nBelow + pAbove * nAbove);

			//cout << "cost at i:" << i << " is " << cost << endl;
			if (cost < bestCost)
			{
				bestCost = cost;
				bestAxis = axis;
				bestOffest = i;// edges[axis][i].type ? i + 1 : i;//When end use next node
			}
		}
		if (edges[axis][i].type == BoundEdge::START)
		{
			++nBelow;
		}
	}
	
	if (retries < 2)//(bestAxis == -1 && retries < 2)//
	{
		++retries;
		axis = (axis + 1) % 3;
		goto RETRY_SPLIT;
	}
	//if no good split, init as leaf
	if (bestAxis == -1)
	{
		node->initLeaf(prims);
		return;
	}

	//recursively build subtree
	vector<int> primsBelow;
	vector<int> primsAbove;
	//Store indices of below primitives
	for (int i = 0; i < bestOffest; ++i)
	{
		if (edges[bestAxis][i].type == BoundEdge::START)
		{
			primsBelow.push_back(edges[bestAxis][i].primNum);
		}
	}
	//Store indices of above primitives
	for (int i = bestOffest + 1; i < np * 2; ++i)
	{
		if (edges[bestAxis][i].type == BoundEdge::END)
		{
			primsAbove.push_back(edges[bestAxis][i].primNum);
		}
	}
	Float tsplit = edges[bestAxis][bestOffest].t;
	node->initInterior(bestAxis, tsplit);

	/*for (int i = 0; i < 2 * np; ++i)
	{
		cout << edges[bestAxis][i].primNum << ": "
			<< edges[bestAxis][i].t << "; Start/End: " << edges[bestAxis][i].type << endl;
	}
	cout << "Split on axis " << axisChar[bestAxis] << " at " << tsplit << endl;
	cout << "Best offset: " << bestOffest << endl;
	cout << "Prims above: ";
	for (int i = 0; i < primsAbove.size(); ++i)
	{
		cout << primsAbove[i] << " ";
	}cout << endl;
	cout << "Prims below: ";
	for (int i = 0; i < primsBelow.size(); ++i)
	{
		cout << primsBelow[i] << " ";
	}cout << endl;
	cout << "////////////////////////" << endl;*/
	Bounds3f belowBound = bound, aboveBound = bound;
	belowBound.pMax[bestAxis] = aboveBound.pMin[bestAxis] = tsplit;

	buildTree(node->belowNode, belowBound, primsBelow, depth - 1, edges);
	buildTree(node->aboveNode, aboveBound, primsAbove, depth - 1, edges);

}
Exemple #2
0
void KdTreeAccel::buildTree(int nodeNum,
        const BBox &nodeBounds,
		const vector<BBox> &allPrimBounds, int *primNums,
		int nPrims, int depth, BoundEdge *edges[3],
		int *prims0, int *prims1, int badRefines) {
	Assert(nodeNum == nextFreeNode); // NOBOOK
	// Get next free node from _nodes_ array
	if (nextFreeNode == nAllocedNodes) {
		int nAlloc = max(2 * nAllocedNodes, 512);
		KdAccelNode *n = (KdAccelNode *)AllocAligned(nAlloc *
			sizeof(KdAccelNode));
		if (nAllocedNodes > 0) {
			memcpy(n, nodes,
			       nAllocedNodes * sizeof(KdAccelNode));
			FreeAligned(nodes);
		}
		nodes = n;
		nAllocedNodes = nAlloc;
	}
	++nextFreeNode;
	// Initialize leaf node if termination criteria met
	if (nPrims <= maxPrims || depth == 0) {
		nodes[nodeNum].initLeaf(primNums, nPrims,
		                       mailboxPrims, arena);
		return;
	}
	// Initialize interior node and continue recursion
	// Choose split axis position for interior node
	int bestAxis = -1, bestOffset = -1;
	float bestCost = INFINITY;
	float oldCost = isectCost * float(nPrims);
	Vector d = nodeBounds.pMax - nodeBounds.pMin;
	float totalSA = (2.f * (d.x*d.y + d.x*d.z + d.y*d.z));
	float invTotalSA = 1.f / totalSA;
	// Choose which axis to split along
	int axis;
	if (d.x > d.y && d.x > d.z) axis = 0;
	else axis = (d.y > d.z) ? 1 : 2;
	int retries = 0;
	retrySplit:
	// Initialize edges for _axis_
	for (int i = 0; i < nPrims; ++i) {
		int pn = primNums[i];
		const BBox &bbox = allPrimBounds[pn];
		edges[axis][2*i] =
		    BoundEdge(bbox.pMin[axis], pn, true);
		edges[axis][2*i+1] =
			BoundEdge(bbox.pMax[axis], pn, false);
	}
	sort(&edges[axis][0], &edges[axis][2*nPrims]);
	// Compute cost of all splits for _axis_ to find best
	int nBelow = 0, nAbove = nPrims;
	for (int i = 0; i < 2*nPrims; ++i) {
		if (edges[axis][i].type == BoundEdge::END) --nAbove;
		float edget = edges[axis][i].t;
		if (edget > nodeBounds.pMin[axis] &&
			edget < nodeBounds.pMax[axis]) {
			// Compute cost for split at _i_th edge
			int otherAxis[3][2] = { {1,2}, {0,2}, {0,1} };
			int otherAxis0 = otherAxis[axis][0];
			int otherAxis1 = otherAxis[axis][1];
			float belowSA = 2 * (d[otherAxis0] * d[otherAxis1] +
			             		(edget - nodeBounds.pMin[axis]) *
				                (d[otherAxis0] + d[otherAxis1]));
			float aboveSA = 2 * (d[otherAxis0] * d[otherAxis1] +
								(nodeBounds.pMax[axis] - edget) *
								(d[otherAxis0] + d[otherAxis1]));
			float pBelow = belowSA * invTotalSA;
			float pAbove = aboveSA * invTotalSA;
			float eb = (nAbove == 0 || nBelow == 0) ? emptyBonus : 0.f;
			float cost = traversalCost + isectCost * (1.f - eb) *
				(pBelow * nBelow + pAbove * nAbove);
			// Update best split if this is lowest cost so far
			if (cost < bestCost)  {
				bestCost = cost;
				bestAxis = axis;
				bestOffset = i;
			}
		}
		if (edges[axis][i].type == BoundEdge::START) ++nBelow;
	}
	Assert(nBelow == nPrims && nAbove == 0); // NOBOOK
	// Create leaf if no good splits were found
	if (bestAxis == -1 && retries < 2) {
		++retries;
		axis = (axis+1) % 3;
		goto retrySplit;
	}
	if (bestCost > oldCost) ++badRefines;
	if ((bestCost > 4.f * oldCost && nPrims < 16) ||
		bestAxis == -1 || badRefines == 3) {
		nodes[nodeNum].initLeaf(primNums, nPrims,
		                     mailboxPrims, arena);
		return;
	}
	// Classify primitives with respect to split
	int n0 = 0, n1 = 0;
	for (int i = 0; i < bestOffset; ++i)
		if (edges[bestAxis][i].type == BoundEdge::START)
			prims0[n0++] = edges[bestAxis][i].primNum;
	for (int i = bestOffset+1; i < 2*nPrims; ++i)
		if (edges[bestAxis][i].type == BoundEdge::END)
			prims1[n1++] = edges[bestAxis][i].primNum;
	// Recursively initialize children nodes
	float tsplit = edges[bestAxis][bestOffset].t;
	nodes[nodeNum].initInterior(bestAxis, tsplit);
	BBox bounds0 = nodeBounds, bounds1 = nodeBounds;
	bounds0.pMax[bestAxis] = bounds1.pMin[bestAxis] = tsplit;
	buildTree(nodeNum+1, bounds0,
		allPrimBounds, prims0, n0, depth-1, edges,
		prims0, prims1 + nPrims, badRefines);
	nodes[nodeNum].aboveChild = nextFreeNode;
	buildTree(nodes[nodeNum].aboveChild, bounds1, allPrimBounds,
		prims1, n1, depth-1, edges,
		prims0, prims1 + nPrims, badRefines);
}
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);
}