示例#1
0
    public BVHNode RecursiveBuild(int start, int end, ref List <RayTracingSubscriber> orderedInfos)
    {
        nodeCreated++;
        //taking the first as start because a new bounds starts at (0, 0, 0) and is considered a box to encapsulate
        Bounds bounds = primitivesInfo[start].bounds;

        for (int i = start + 1; i < end; i++)
        {
            bounds.Encapsulate(primitivesInfo[i].bounds);
        }

        int primitives = end - start;
        int mid        = (end + start) / 2;
        int axis       = -1;

        //we create a node, we can't divide anymore
        if (primitives == 1)
        {
//            Debug.Log("Creating a node cause 1 primitive remains");
            int primitivesOffset = orderedInfos.Count;

            int primitiveNumber = primitivesInfo[start].primitiveIndex;
            orderedInfos.Add(subs[primitiveNumber]);

            return(new BVHNode(primitivesOffset, 1, bounds));
        }
        else //subdivide
        {
            //we select the best axis to split
            Bounds centroidBounds = new Bounds();
            centroidBounds.center = primitivesInfo[start].bounds.center;

            for (int i = start + 1; i < end; i++)
            {
                centroidBounds.Encapsulate(primitivesInfo[i].bounds.center);
            }

            axis = GetMaximumExtentAxis(centroidBounds);

            //if the boxes are aligned
            //super strange case which should not occur
            if (Math.Abs(centroidBounds.max[axis] - centroidBounds.min[axis]) < 0.0001f)
            {
                int primitivesOffset = orderedInfos.Count;
                for (int i = start; i < end; i++)
                {
                    int primitiveNumber = primitivesInfo[i].primitiveIndex;
                    orderedInfos.Add(subs[primitiveNumber]);
                }

                return(new BVHNode(primitivesOffset, primitives, bounds));
            }
            else
            {
                if (primitives <= 2)
                {
                    //using equally sized subsets as it's cheaper
                    //just swap the 2 primitives
                    // if a.centroid[dim] < b.centroid[dim]
                    // Debug.Log(start);
                    // Debug.Log(end);
                    // Debug.Log(mid);
                    var prim0 = primitivesInfo[start];
                    var prim1 = primitivesInfo[start + 1];

                    if (prim0.bounds.center[axis] > prim1.bounds.center[axis])
                    {
                        primitivesInfo[start]     = prim1;
                        primitivesInfo[start + 1] = prim0;
                    }
                }
                else
                {
                    //We compute the buckets count and bounds

                    for (int i = start; i < end; i++)
                    {
                        int bucket = (int)(nBuckets * GetRelativePosition(centroidBounds, primitivesInfo[i].bounds.center)[axis]);

                        //the last bucket is useless for subdividing
                        if (bucket == nBuckets)
                        {
                            bucket = nBuckets - 1;
                        }

                        buckets[bucket].count++;
                        buckets[bucket].bounds.Encapsulate(primitivesInfo[i].bounds);
                    }

                    //computing the cost for splitting each bucket

                    float[] costs = new float[nBuckets];

                    //formula of the cost = Ttrav + pA * sum(Tisect(a[i])) + pB * sum(Tisect(b[i]))

                    //following a bit the pbr book for the values
                    //Ttrav will be 0.5f relative to the cost of dividing

                    //computing the cost of splitting
                    for (int i = 0; i < nBuckets - 1; i++)
                    {
                        Bounds b0     = buckets[0].bounds;
                        int    count0 = buckets[0].count;

                        Bounds b1     = buckets[i + 1].bounds;
                        int    count1 = buckets[i + 1].count;

                        //left side of the division
                        for (int j = 1; j <= i; j++)
                        {
                            b0.Encapsulate(buckets[j].bounds);
                            count0 += buckets[j].count;
                        }

                        for (int j = i + 2; j < nBuckets; j++)
                        {
                            b1.Encapsulate(buckets[j].bounds);
                            count1 += buckets[j].count;
                        }

                        costs[i] = 0.5f
                                   + (count0 * GetSurfaceArea(b0) + count1 * GetSurfaceArea(b1))
                                   / GetSurfaceArea(bounds);
                    }

                    //find the min bucket, to minimize the cost
                    float minCost            = costs[0];
                    int   minCostSplitBucket = 0;

                    for (int i = 1; i < nBuckets - 1; i++)
                    {
                        if (minCost > costs[i])
                        {
                            minCost            = costs[i];
                            minCostSplitBucket = i;
                        }
                    }

                    float leafCost = primitives;

                    //the cost of creating a leaf is greater than the bucket chosen
                    if (primitives > maxPrimsInNode || minCost < leafCost)
                    {
                        //reorders the array of primsInfo
                        //resets the mid
                        List <PrimitiveInfo> trueList  = new List <PrimitiveInfo>(end - start);
                        List <PrimitiveInfo> falseList = new List <PrimitiveInfo>(end - start);

                        for (int i = start; i < end; i++)
                        {
                            int bucket = (int)(nBuckets * GetRelativePosition(centroidBounds, primitivesInfo[i].bounds.center)[axis]);

                            //the last bucket is useless for subdividing
                            if (bucket == nBuckets)
                            {
                                bucket = nBuckets - 1;
                            }

                            if (bucket <= minCostSplitBucket)
                            {
                                trueList.Add(primitivesInfo[i]);
                            }
                            else
                            {
                                falseList.Add(primitivesInfo[i]);
                            }
                        }

                        mid = start + trueList.Count;

                        //actually splitting
                        for (int i = 0; i < trueList.Count; i++)
                        {
                            primitivesInfo[i + start] = trueList[i];
                        }

                        for (int i = 0; i < falseList.Count; i++)
                        {
                            primitivesInfo[i + mid] = falseList[i];
                        }
                    }
                    else //we create a leaf
                    {
                        int primitivesOffset = orderedInfos.Count;
                        for (int i = start; i < end; i++)
                        {
                            int primitiveNumber = primitivesInfo[i].primitiveIndex;
                            orderedInfos.Add(subs[primitiveNumber]);
                        }

                        return(new BVHNode(primitivesOffset, primitives, bounds));
                    }
                }
            }
        }

        BVHNode node = new BVHNode(0, 0, new Bounds());

        node.InitChildren(RecursiveBuild(start, mid, ref orderedInfos),
                          RecursiveBuild(mid, end, ref orderedInfos), axis);

        return(node);
    }