List <LinearBVHNode> nodes; //改为array? // BVHAccel Method Definitions public void InitBVHAccel(List <BaseShape> p, int mp, string sm) { maxPrimsInNode = Max(255, mp); Shapes = p; var shapeCount = Shapes.Count; if (shapeCount == 0) { nodes = null; return; } // Initialize _buildData_ array for Shapes List <BVHShapeInfo> buildData = new List <BVHShapeInfo>(shapeCount); for (int i = 0; i < shapeCount; ++i) { AABB bbox = Shapes[i].GetBound(); buildData.Add(new BVHShapeInfo(i, bbox)); } // Recursively build BVH tree for Shapes MemoryArena buildArena = new MemoryArena(); int totalNodes = 0; List <Shape> orderedPrims = new List <BaseShape>(shapeCount); BVHBuildNode root = recursiveBuild(buildArena, buildData, 0, Shapes.Count, ref totalNodes, orderedPrims); // Compute representation of depth-first traversal of BVH tree nodes = new List <LinearBVHNode>(totalNodes); int offset = 0; //flattenBVHTree(root, &offset); }
BVHBuildNode recursiveBuild(MemoryArena buildArena, List <BVHShapeInfo> buildData, int start, int end, ref int totalNodes, List <Shape> orderedPrims) { Debug.Assert(start != end); ++totalNodes; BVHBuildNode node = buildArena.AllocOne <BVHBuildNode>(); // Compute bounds of all Shapes in BVH node AABB bbox = new AABB(buildData[start].bounds); for (int i = start + 1; i < end; ++i) { bbox = Union(bbox, buildData[i].bounds); } int nShapes = end - start; if (nShapes == 1) { // Create leaf _BVHBuildNode_ int firstPrimOffset = orderedPrims.Count; for (int i = start; i < end; ++i) { int primNum = buildData[i].ShapeNumber; orderedPrims.Add(Shapes[primNum]); } node.InitLeaf(firstPrimOffset, nShapes, bbox); } else { // Compute bound of Shape centroids, choose split dimension _dim_ AABB centroidBounds = new AABB(buildData[start].bounds); for (int i = start; i < end; ++i) { centroidBounds = Union(centroidBounds, buildData[i].centroid); } int dim = centroidBounds.MaximumExtent(); // Partition Shapes into two sets and build children int mid = (start + end) / 2; if (centroidBounds.max[dim] == centroidBounds.min[dim]) { // If nShapes is no greater than maxPrimsInNode, // then all the nodes can be stored in a compact bvh node. if (nShapes <= maxPrimsInNode) { // Create leaf _BVHBuildNode_ int firstPrimOffset = orderedPrims.Count; for (int i = start; i < end; ++i) { int primNum = buildData[i].ShapeNumber; orderedPrims.Add(Shapes[primNum]); } node.InitLeaf(firstPrimOffset, nShapes, bbox); return(node); } else { // else if nShapes is greater than maxPrimsInNode, we // need to split it further to guarantee each node contains // no more than maxPrimsInNode Shapes. node.InitInterior(dim, recursiveBuild(buildArena, buildData, start, mid, ref totalNodes, orderedPrims), recursiveBuild(buildArena, buildData, mid, end, ref totalNodes, orderedPrims)); return(node); } } // Partition Shapes based on _splitMethod_ // Partition Shapes using approximate SAH if (nShapes <= 4) { // Partition Shapes into equally-sized subsets mid = (start + end) / 2; NthElement(buildData, start, mid, end, new ComparePoints(dim).Compare); } else { // Allocate _BucketInfo_ for SAH partition buckets int nBuckets = 12; BucketInfo[] buckets = new BucketInfo[nBuckets]; // Initialize _BucketInfo_ for SAH partition buckets for (int i = start; i < end; ++i) { int b = (nBuckets * ( (buildData[i].centroid[dim] - centroidBounds.min[dim]) / (centroidBounds.max[dim] - centroidBounds.min[dim]))).ToInt(); if (b == nBuckets) { b = nBuckets - 1; } Debug.Assert(b >= 0 && b < nBuckets); buckets[b].count++; buckets[b].bounds = Union(buckets[b].bounds, buildData[i].bounds); } // Compute costs for splitting after each bucket LFloat[] cost = new LFloat[nBuckets - 1]; for (int i = 0; i < nBuckets - 1; ++i) { var b0 = new AABB(); var b1 = new AABB(); 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] = LFloat.one / 8 + (count0 * b0.SurfaceArea() + count1 * b1.SurfaceArea()) / bbox.SurfaceArea(); } // Find bucket to split at that minimizes SAH metric LFloat minCost = cost[0]; int minCostSplit = 0; for (int i = 1; i < nBuckets - 1; ++i) { if (cost[i] < minCost) { minCost = cost[i]; minCostSplit = i; } } // Either create leaf or split Shapes at selected SAH bucket if (nShapes > maxPrimsInNode || minCost < nShapes) { //var func = ; int pmid = Partition(buildData, start, end, new CompareToBucket(minCostSplit, nBuckets, dim, centroidBounds).Compare); mid = pmid - 0; } else { // Create leaf _BVHBuildNode_ int firstPrimOffset = orderedPrims.Count; for (int i = start; i < end; ++i) { int primNum = buildData[i].ShapeNumber; orderedPrims.Add(Shapes[primNum]); } node.InitLeaf(firstPrimOffset, nShapes, bbox); return(node); } } node.InitInterior(dim, recursiveBuild(buildArena, buildData, start, mid, ref totalNodes, orderedPrims), recursiveBuild(buildArena, buildData, mid, end, ref totalNodes, orderedPrims)); } return(node); }