void BVHTree::BuildNode(BVHNode *node, const objPtr_t *objPtrs, const Aabb *objAabbs, std::vector<objPtr_t> &activeObjIdx) { const int numTris = activeObjIdx.size(); if (numTris <= 0) Error("BuildNode called with no elements in activeObjIndex."); if (numTris == 1) { MakeLeaf(node, objPtrs, activeObjIdx); return; } std::vector<int> splitSides(numTris); Aabb aabb; aabb.min = vector3d(FLT_MAX, FLT_MAX, FLT_MAX); aabb.max = vector3d(-FLT_MAX, -FLT_MAX, -FLT_MAX); for (int i=0; i<numTris; i++) { int idx = activeObjIdx[i]; aabb.Update(objAabbs[idx].min); aabb.Update(objAabbs[idx].max); } node->numTris = numTris; node->aabb = aabb; Aabb splitBox = aabb; double splitPos; int splitAxis; int s1count, s2count; int attempt = 0; for (;;) { splitAxis = 0; vector3d boxSize = splitBox.max - splitBox.min; if (boxSize[1] > boxSize[0]) splitAxis = 1; if ((boxSize[2] > boxSize[1]) && (boxSize[2] > boxSize[0])) splitAxis = 2; // split pos in middle of splitBox splitPos = 0.5f * (splitBox.min[splitAxis] + splitBox.max[splitAxis]); s1count = 0, s2count = 0; for (int i=0; i<numTris; i++) { int idx = activeObjIdx[i]; double mid = 0.5 * (objAabbs[idx].min[splitAxis] + objAabbs[idx].max[splitAxis]); if (mid < splitPos) { splitSides[i] = 0; s1count++; } else { splitSides[i] = 1; s2count++; } } if (s1count == numTris) { if (attempt < MAX_SPLITPOS_RETRIES) { // try splitting at average point splitBox.max[splitAxis] = splitPos; attempt++; continue; } else { MakeLeaf(node, objPtrs, activeObjIdx); return; } } else if (s2count == numTris) { if (attempt < MAX_SPLITPOS_RETRIES) { // try splitting at average point splitBox.min[splitAxis] = splitPos; attempt++; continue; } else { MakeLeaf(node, objPtrs, activeObjIdx); return; } } break; } std::vector<int> side[2]; for (int i=0; i<numTris; i++) { side[splitSides[i]].push_back(activeObjIdx[i]); } // recurse! node->triIndicesStart = 0; node->kids[0] = AllocNode(); node->kids[1] = AllocNode(); BuildNode(node->kids[0], objPtrs, objAabbs, side[0]); BuildNode(node->kids[1], objPtrs, objAabbs, side[1]); }