예제 #1
0
        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);
        }
예제 #2
0
 public void InitInterior(int axis, BVHBuildNode c0, BVHBuildNode c1)
 {
     childLeft  = c0;
     childRight = c1;
     bounds     = Union(c0.bounds, c1.bounds);
     splitAxis  = axis;
     nShapes    = 0;
 }
예제 #3
0
        int flattenBVHTree(BVHBuildNode node, ref int offset)
        {
            LinearBVHNode linearNode = nodes[offset];

            linearNode.bounds = node.bounds;
            int myOffset = offset++;

            if (node.nShapes > 0)
            {
                Debug.Assert(node.childLeft != null && node.childRight != null);
                linearNode.ShapesOffset = node.firstPrimOffset;
                linearNode.nShapes      = (byte)node.nShapes;
            }
            else
            {
                // Creater interior flattened BVH node
                linearNode.axis    = (byte)node.splitAxis;
                linearNode.nShapes = 0;
                flattenBVHTree(node.childLeft, ref offset);
                linearNode.secondChildOffset = flattenBVHTree(node.childRight, ref offset);
            }

            return(myOffset);
        }
예제 #4
0
        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);
        }