void JRTHeuristicKDTreeBuilder::BuildTreeImpl(const JRTBoundingBox& rBounds, const std::vector<const JRTTriangle*>& rTris, std::vector<JRTKDNode>& rNodesOut, std::vector<UINT>& rTrisOut) { rNodesOut.push_back(JRTKDNode()); // create root node // extract triangle BBs BuildBBs(rTris, m_bbs); // extract split planes std::vector<Split> splits[3]; for (int i = 0; i < 3; i++) { ExtractSplits(i, m_bbs, splits[i], rBounds); } // build vectors of pointers to these split planes for shuffling around SplitVec splitPtrs[3]; for (int i = 0; i < 3; i++) { splitPtrs[i].resize(splits[i].size()); for (int j = 0; j < (int)splits[i].size(); j++) { splitPtrs[i][j] = &splits[i][j]; } } // build vectors of pointers to BBs, also for shuffling around std::vector<TriangleBB*> bbPtrs; for (int i = 0; i < (int)m_bbs.size(); i++) { bbPtrs.push_back(&m_bbs[i]); } BuildTreeRecursive(JRTKDTree::MAX_TREE_DEPTH, rBounds, splitPtrs, bbPtrs, &rNodesOut[0], rNodesOut, rTrisOut); }
void JRTKDTreeBuilder::BuildTreeImpl(const JRTBoundingBox& rBounds, const std::vector<const JRTTriangle*>& rTris, std::vector<JRTKDNode>& rNodesOut, std::vector<UINT>& rTriIndicesOut) { rNodesOut.push_back(JRTKDNode()); // create root node std::vector<UINT> rIndices; for (UINT i = 0; i < rTris.size(); i++) { rIndices.push_back(i); } // construct the tree using our naive tree building function BuildTreeSimple(&rNodesOut[0], rTris, rIndices, rBounds, JRTKDTree::MAX_TREE_DEPTH, rNodesOut, rTriIndicesOut); }
void BuildTreeSimple(JRTKDNode* current_node, const std::vector<const JRTTriangle*>& triangles_in, const std::vector<UINT>& rIndicesIn, const JRTBoundingBox& scene_bounds, UINT depth_max, std::vector<JRTKDNode>& nodes_out, std::vector<UINT>& rTriIndicesOut) { if (depth_max == 0 || rIndicesIn.size() < 25) { // make leaf current_node->leaf.is_leaf = true; current_node->leaf.triangle_start = (UINT) rTriIndicesOut.size(); current_node->leaf.triangle_count = (UINT) rIndicesIn.size(); for (UINT i = 0; i < rIndicesIn.size(); i++) { rTriIndicesOut.push_back(rIndicesIn[i]); } return; } // choose best split plane and split node bounding box float diffs[3]; Axis maxcomp = X_AXIS; // choose split plane based on longest BBox axis JRTBoundingBox front_bounds(scene_bounds); JRTBoundingBox back_bounds(scene_bounds); for (int i = X_AXIS; i < Z_AXIS; i++) { diffs[i] = scene_bounds.GetMax()[i] - scene_bounds.GetMin()[i]; if (diffs[i] > diffs[maxcomp]) { maxcomp = (Axis)i; } } float splitval = 0.5f * diffs[maxcomp] + scene_bounds.GetMin()[maxcomp]; front_bounds.GetMin()[maxcomp] = splitval; back_bounds.GetMax()[maxcomp] = splitval; // partition polygons std::vector<UINT> front_polys; std::vector<UINT> back_polys; PartitionTriangles(triangles_in, rIndicesIn, (Axis)maxcomp, splitval, front_polys, back_polys); // make current node an inner node current_node->leaf.is_leaf = false; current_node->inner.axis = (UBYTE)maxcomp; current_node->inner.position = splitval; current_node->inner.front_offset = (UINT)nodes_out.size(); UINT front_child = (UINT)nodes_out.size(); UINT back_child = (UINT)nodes_out.size() + 1; // always allocate left child next to right child nodes_out.push_back(JRTKDNode()); nodes_out.push_back(JRTKDNode()); // recursively continue tree construction BuildTreeSimple(&nodes_out[front_child], triangles_in, front_polys, front_bounds, depth_max - 1, nodes_out, rTriIndicesOut); BuildTreeSimple(&nodes_out[back_child], triangles_in, back_polys, back_bounds, depth_max - 1, nodes_out, rTriIndicesOut); }
void JRTHeuristicKDTreeBuilder::BuildTreeRecursive(UINT nDepthLimit, const JRTBoundingBox& rNodeBounds, SplitVec splits[3], std::vector<TriangleBB*>& rBBsThisNode, JRTKDNode* pNode, std::vector<JRTKDNode>& rNodesOut, std::vector<UINT>& rTrisOut) { UINT nTriCount = (UINT)rBBsThisNode.size(); JRT_ASSERT(splits[0].size() == splits[1].size() && splits[1].size() == splits[2].size()); // initialize best cost to cost of not splitting float fBestCost = INTERSECT_COST * nTriCount; // find the optimal split bool bSplit = false; float fSplitValue; UINT eSplitAxis = X_AXIS; float fNodeBBInvArea = 1.0f / Max(0.0000001f, rNodeBounds.GetSurfaceArea()); float fNodeVolume = rNodeBounds.GetVolume(); for (UINT axis = X_AXIS; axis <= Z_AXIS; axis++) { LocateBestSplit(fNodeBBInvArea, rNodeBounds, splits, axis, nTriCount, fBestCost, bSplit, eSplitAxis, fSplitValue); } if (!bSplit || nDepthLimit == 0) { // we either don't want to split, or can't split, so make a leaf pNode->leaf.is_leaf = true; pNode->leaf.triangle_count = 0; pNode->leaf.triangle_start = (UINT)rTrisOut.size(); for (UINT i = 0; i < rBBsThisNode.size(); i++) { // do robust tri-box clipping at the leaves const Vec3f* pV1 = &rBBsThisNode[i]->pTri->GetV1(); const Vec3f* pV2 = &rBBsThisNode[i]->pTri->GetV2(); const Vec3f* pV3 = &rBBsThisNode[i]->pTri->GetV3(); if (rNodeBounds.TriangleIntersect(pV1, pV2, pV3)) { rTrisOut.push_back(rBBsThisNode[i]->nIndex); pNode->leaf.triangle_count++; } } } else { // make a non-leaf pNode->inner.axis = eSplitAxis; pNode->inner.is_leaf = false; pNode->inner.position = fSplitValue; JRT_ASSERT(fSplitValue > rNodeBounds.GetMin()[eSplitAxis] && fSplitValue < rNodeBounds.GetMax()[eSplitAxis]); ClassifyBBs(splits[0], m_bbs, eSplitAxis, fSplitValue); // partition the splits SplitVec frontSplits[3]; SplitVec backSplits[3]; for (int j = X_AXIS; j <= Z_AXIS; j++) { PartitionSplits(fSplitValue, eSplitAxis, splits[j], m_bbs, backSplits[j], frontSplits[j]); // clear old split vec to save memory splits[j].clear(); } // partition BBs std::vector<TriangleBB*> backBBs; std::vector<TriangleBB*> frontBBs; PartitionBBs(eSplitAxis, fSplitValue, rBBsThisNode, backBBs, frontBBs); rBBsThisNode.clear(); // save memory // create new nodes // by convention, always create front child right before back child pNode->inner.front_offset = (UINT)rNodesOut.size(); UINT nFront = (UINT)rNodesOut.size(); UINT nBack = nFront + 1; rNodesOut.push_back(JRTKDNode()); rNodesOut.push_back(JRTKDNode()); // split the node bounding box JRTBoundingBox front_bounds, back_bounds; rNodeBounds.Split(eSplitAxis, fSplitValue, front_bounds, back_bounds); // recursively build the subtrees BuildTreeRecursive(nDepthLimit - 1, front_bounds, frontSplits, frontBBs, &rNodesOut[ nFront ], rNodesOut, rTrisOut); BuildTreeRecursive(nDepthLimit - 1, back_bounds, backSplits, backBBs, &rNodesOut[ nBack ], rNodesOut, rTrisOut); } }