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); }
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); }