void buildHierarchy(List <uint> tempTree, buildData dat, BuildStats stats) { // create space for the first node tempTree.Add(3u << 30); // dummy leaf tempTree.Add(0); tempTree.Add(0); // seed bbox AABound gridBox = new(); gridBox.lo = bounds.Lo; gridBox.hi = bounds.Hi; AABound nodeBox = gridBox; // seed subdivide function subdivide(0, (int)(dat.numPrims - 1), tempTree, dat, gridBox, nodeBox, 0, 1, stats); }
void subdivide(int left, int right, List <uint> tempTree, buildData dat, AABound gridBox, AABound nodeBox, int nodeIndex, int depth, BuildStats stats) { if ((right - left + 1) <= dat.maxPrims || depth >= 64) { // write leaf node stats.updateLeaf(depth, right - left + 1); createNode(tempTree, nodeIndex, left, right); return; } // calculate extents int axis = -1, prevAxis, rightOrig; float clipL = float.NaN, clipR = float.NaN, prevClip = float.NaN; float split = float.NaN, prevSplit; bool wasLeft = true; while (true) { prevAxis = axis; prevSplit = split; // perform quick consistency checks Vector3 d = gridBox.hi - gridBox.lo; // find longest axis axis = (int)d.PrimaryAxis(); split = 0.5f * (gridBox.lo.GetAt(axis) + gridBox.hi.GetAt(axis)); // partition L/R subsets clipL = float.NegativeInfinity; clipR = float.PositiveInfinity; rightOrig = right; // save this for later float nodeL = float.PositiveInfinity; float nodeR = float.NegativeInfinity; for (int i = left; i <= right;) { uint obj = dat.indices[i]; float minb = dat.primBound[obj].Lo.GetAt(axis); float maxb = dat.primBound[obj].Hi.GetAt(axis); float center = (minb + maxb) * 0.5f; if (center <= split) { // stay left i++; if (clipL < maxb) { clipL = maxb; } } else { // move to the right most uint t = dat.indices[i]; dat.indices[i] = dat.indices[right]; dat.indices[right] = t; right--; if (clipR > minb) { clipR = minb; } } nodeL = Math.Min(nodeL, minb); nodeR = Math.Max(nodeR, maxb); } // check for empty space if (nodeL > nodeBox.lo.GetAt(axis) && nodeR < nodeBox.hi.GetAt(axis)) { float nodeBoxW = nodeBox.hi.GetAt(axis) - nodeBox.lo.GetAt(axis); float nodeNewW = nodeR - nodeL; // node box is too big compare to space occupied by primitives? if (1.3f * nodeNewW < nodeBoxW) { stats.updateBVH2(); int nextIndex1 = tempTree.Count(); // allocate child tempTree.Add(0); tempTree.Add(0); tempTree.Add(0); // write bvh2 clip node stats.updateInner(); tempTree[nodeIndex + 0] = (uint)((axis << 30) | (1 << 29) | nextIndex1); tempTree[nodeIndex + 1] = floatToRawIntBits(nodeL); tempTree[nodeIndex + 2] = floatToRawIntBits(nodeR); // update nodebox and recurse nodeBox.lo.SetAt(nodeL, axis); nodeBox.hi.SetAt(nodeR, axis); subdivide(left, rightOrig, tempTree, dat, gridBox, nodeBox, nextIndex1, depth + 1, stats); return; } } // ensure we are making progress in the subdivision if (right == rightOrig) { // all left if (prevAxis == axis && MathFunctions.fuzzyEq(prevSplit, split)) { // we are stuck here - create a leaf stats.updateLeaf(depth, right - left + 1); createNode(tempTree, nodeIndex, left, right); return; } if (clipL <= split) { // keep looping on left half gridBox.hi.SetAt(split, axis); prevClip = clipL; wasLeft = true; continue; } gridBox.hi.SetAt(split, axis); prevClip = float.NaN; } else if (left > right) { // all right right = rightOrig; if (prevAxis == axis && MathFunctions.fuzzyEq(prevSplit, split)) { // we are stuck here - create a leaf stats.updateLeaf(depth, right - left + 1); createNode(tempTree, nodeIndex, left, right); return; } if (clipR >= split) { // keep looping on right half gridBox.lo.SetAt(split, axis); prevClip = clipR; wasLeft = false; continue; } gridBox.lo.SetAt(split, axis); prevClip = float.NaN; } else { // we are actually splitting stuff if (prevAxis != -1 && !float.IsNaN(prevClip)) { // second time through - lets create the previous split // since it produced empty space int nextIndex0 = tempTree.Count; // allocate child node tempTree.Add(0); tempTree.Add(0); tempTree.Add(0); if (wasLeft) { // create a node with a left child // write leaf node stats.updateInner(); tempTree[nodeIndex + 0] = (uint)((prevAxis << 30) | nextIndex0); tempTree[nodeIndex + 1] = floatToRawIntBits(prevClip); tempTree[nodeIndex + 2] = floatToRawIntBits(float.PositiveInfinity); } else { // create a node with a right child // write leaf node stats.updateInner(); tempTree[nodeIndex + 0] = (uint)((prevAxis << 30) | (nextIndex0 - 3)); tempTree[nodeIndex + 1] = floatToRawIntBits(float.NegativeInfinity); tempTree[nodeIndex + 2] = floatToRawIntBits(prevClip); } // count stats for the unused leaf depth++; stats.updateLeaf(depth, 0); // now we keep going as we are, with a new nodeIndex: nodeIndex = nextIndex0; } break; } } // compute index of child nodes int nextIndex = tempTree.Count; // allocate left node int nl = right - left + 1; int nr = rightOrig - (right + 1) + 1; if (nl > 0) { tempTree.Add(0); tempTree.Add(0); tempTree.Add(0); } else { nextIndex -= 3; } // allocate right node if (nr > 0) { tempTree.Add(0); tempTree.Add(0); tempTree.Add(0); } // write leaf node stats.updateInner(); tempTree[nodeIndex + 0] = (uint)((axis << 30) | nextIndex); tempTree[nodeIndex + 1] = floatToRawIntBits(clipL); tempTree[nodeIndex + 2] = floatToRawIntBits(clipR); // prepare L/R child boxes AABound gridBoxL = gridBox; AABound gridBoxR = gridBox; AABound nodeBoxL = nodeBox; AABound nodeBoxR = nodeBox; gridBoxR.lo.SetAt(split, axis); gridBoxL.hi.SetAt(split, axis); nodeBoxL.hi.SetAt(clipL, axis); nodeBoxR.lo.SetAt(clipR, axis); // recurse if (nl > 0) { subdivide(left, right, tempTree, dat, gridBoxL, nodeBoxL, nextIndex, depth + 1, stats); } else { stats.updateLeaf(depth + 1, 0); } if (nr > 0) { subdivide(right + 1, rightOrig, tempTree, dat, gridBoxR, nodeBoxR, nextIndex + 3, depth + 1, stats); } else { stats.updateLeaf(depth + 1, 0); } }