private BVHBuildNode RecursiveBuild(List <BVHPrimitiveInfo> primitiveInfo, int start, int end, ref int totalNodes, List <Primitive> orderedPrims) { //CHECK_NE(start, end); BVHBuildNode node = new BVHBuildNode(); totalNodes++; // Compute bounds of all primitives in BVH node Bounds3D bounds = new Bounds3D(); for (int i = start; i < end; ++i) { bounds = bounds.Union(primitiveInfo[i]._bounds); } int nPrimitives = end - start; if (nPrimitives == 1) { // Create leaf _BVHBuildNode_ int firstPrimOffset = orderedPrims.Count; for (int i = start; i < end; ++i) { int primNum = primitiveInfo[i]._primitiveNumber; orderedPrims.Add(primitives[primNum]); } node.InitLeaf(firstPrimOffset, nPrimitives, bounds); return(node); } else { // Compute bound of primitive centroids, choose split dimension _dim_ Bounds3D centroidBounds = new Bounds3D(); for (int i = start; i < end; ++i) { centroidBounds = centroidBounds.Union(primitiveInfo[i]._centroid); } int dim = centroidBounds.MaximumExtent; // Partition primitives into two sets and build children int mid = (start + end) / 2; if (centroidBounds.MaxPoint[dim] == centroidBounds.MinPoint[dim]) { // Create leaf _BVHBuildNode_ int firstPrimOffset = orderedPrims.Count; for (int i = start; i < end; ++i) { int primNum = primitiveInfo[i]._primitiveNumber; orderedPrims.Add(primitives[primNum]); } node.InitLeaf(firstPrimOffset, nPrimitives, bounds); return(node); } else { // Partition primitives based on _splitMethod_ // todo: implement me!!! //switch (splitMethod) //{ // case SplitMethod.Middle: // { // // Partition primitives through node's midpoint // double pmid = // (centroidBounds.MinPoint[dim] + centroidBounds.MaxPoint[dim]) / 2.0; // BVHPrimitiveInfo* midPtr = std::partition( // &primitiveInfo[start], &primitiveInfo[end - 1] + 1, // [dim, pmid](const BVHPrimitiveInfo &pi) { // return pi.centroid[dim] < pmid; // }); // mid = midPtr - primitiveInfo[0]; // // For lots of prims with large overlapping bounding boxes, this // // may fail to partition; in that case don't break and fall // // through // // to EqualCounts. // if (mid != start && mid != end) // { // break; // } // } // case SplitMethod.EqualCounts: // { // // Partition primitives into equally-sized subsets // mid = (start + end) / 2; // std::nth_element(&primitiveInfo[start], &primitiveInfo[mid], // &primitiveInfo[end - 1] + 1, // [dim](const BVHPrimitiveInfo &a, // const BVHPrimitiveInfo &b) { // return a.centroid[dim] < b.centroid[dim]; // }); // break; // } // case SplitMethod.SAH: // default: // { // // Partition primitives using approximate SAH // if (nPrimitives <= 2) // { // // Partition primitives into equally-sized subsets // mid = (start + end) / 2; // std::nth_element(&primitiveInfo[start], &primitiveInfo[mid], // &primitiveInfo[end - 1] + 1, // [dim](const BVHPrimitiveInfo &a, // const BVHPrimitiveInfo &b) { // return a.centroid[dim] < // b.centroid[dim]; // }); // } // else // { // // Allocate _BucketInfo_ for SAH partition buckets // PBRT_CONSTEXPR int nBuckets = 12; // BucketInfo buckets[nBuckets]; // // Initialize _BucketInfo_ for SAH partition buckets // for (int i = start; i < end; ++i) // { // int b = nBuckets * // centroidBounds.Offset( // primitiveInfo[i].centroid)[dim]; // if (b == nBuckets) b = nBuckets - 1; // CHECK_GE(b, 0); // CHECK_LT(b, nBuckets); // buckets[b].count++; // buckets[b].bounds = // Union(buckets[b].bounds, primitiveInfo[i].bounds); // } // // Compute costs for splitting after each bucket // Float cost[nBuckets - 1]; // for (int i = 0; i < nBuckets - 1; ++i) // { // Bounds3f b0, b1; // int count0 = 0, count1 = 0; // for (int j = 0; j <= i; ++j) // { // b0 = Union(b0, buckets[j].bounds); // count0 += buckets[j].count; // } // for (int j = i + 1; j < nBuckets; ++j) // { // b1 = Union(b1, buckets[j].bounds); // count1 += buckets[j].count; // } // cost[i] = 1 + // (count0 * b0.SurfaceArea() + // count1 * b1.SurfaceArea()) / // bounds.SurfaceArea(); // } // // Find bucket to split at that minimizes SAH metric // Float minCost = cost[0]; // int minCostSplitBucket = 0; // for (int i = 1; i < nBuckets - 1; ++i) // { // if (cost[i] < minCost) // { // minCost = cost[i]; // minCostSplitBucket = i; // } // } // // Either create leaf or split primitives at selected SAH // // bucket // Float leafCost = nPrimitives; // if (nPrimitives > maxPrimsInNode || minCost < leafCost) // { // BVHPrimitiveInfo* pmid = std::partition( // &primitiveInfo[start], &primitiveInfo[end - 1] + 1, // [=](const BVHPrimitiveInfo &pi) { // int b = nBuckets * // centroidBounds.Offset(pi.centroid)[dim]; // if (b == nBuckets) b = nBuckets - 1; // CHECK_GE(b, 0); // CHECK_LT(b, nBuckets); // return b <= minCostSplitBucket; // }); // mid = pmid - &primitiveInfo[0]; // } // else // { // // Create leaf _BVHBuildNode_ // int firstPrimOffset = orderedPrims.size(); // for (int i = start; i < end; ++i) // { // int primNum = primitiveInfo[i].primitiveNumber; // orderedPrims.push_back(primitives[primNum]); // } // node->InitLeaf(firstPrimOffset, nPrimitives, bounds); // return node; // } // } // break; // } //} node.InitInterior(dim, RecursiveBuild(primitiveInfo, start, mid, ref totalNodes, orderedPrims), RecursiveBuild(primitiveInfo, mid, end, ref totalNodes, orderedPrims)); } } return(node); }