private void subdivide(int left, int right, List <int> tempTree, int[] indices, float[] gridBox, float[] nodeBox, int nodeIndex, int depth, BuildStats stats)
        {
            if ((right - left + 1) <= 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
                float[] d = { gridBox[1] - gridBox[0], gridBox[3] - gridBox[2],
                              gridBox[5] - gridBox[4] };
                if (d[0] < 0 || d[1] < 0 || d[2] < 0)
                {
                    throw new Exception("negative node extents");
                }
                for (int i = 0; i < 3; i++)
                {
                    if (nodeBox[2 * i + 1] < gridBox[2 * i] || nodeBox[2 * i] > gridBox[2 * i + 1])
                    {
                        UI.printError(UI.Module.ACCEL, "Reached tree area in error - discarding node with: {0} objects", right - left + 1);
                        throw new Exception("invalid node overlap");
                    }
                }
                // find longest axis
                if (d[0] > d[1] && d[0] > d[2])
                {
                    axis = 0;
                }
                else if (d[1] > d[2])
                {
                    axis = 1;
                }
                else
                {
                    axis = 2;
                }
                split = 0.5f * (gridBox[2 * axis] + gridBox[2 * axis + 1]);
                // 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;)
                {
                    int   obj    = indices[i];
                    float minb   = primitives.getPrimitiveBound(obj, 2 * axis + 0);
                    float maxb   = primitives.getPrimitiveBound(obj, 2 * axis + 1);
                    float center = (minb + maxb) * 0.5f;
                    if (center <= split)
                    {
                        // stay left
                        i++;
                        if (clipL < maxb)
                        {
                            clipL = maxb;
                        }
                    }
                    else
                    {
                        // move to the right most
                        int t = indices[i];
                        indices[i]     = indices[right];
                        indices[right] = t;
                        right--;
                        if (clipR > minb)
                        {
                            clipR = minb;
                        }
                    }
                    if (nodeL > minb)
                    {
                        nodeL = minb;
                    }
                    if (nodeR < maxb)
                    {
                        nodeR = maxb;
                    }
                }
                // check for empty space
                if (nodeL > nodeBox[2 * axis + 0] && nodeR < nodeBox[2 * axis + 1])
                {
                    float nodeBoxW = nodeBox[2 * axis + 1] - nodeBox[2 * axis + 0];
                    float nodeNewW = nodeR - nodeL;
                    // node box is too big compare to space occupied by primitives?
                    if (1.3f * nodeNewW < nodeBoxW)
                    {
                        stats.updateBVH2();
                        int nextIndex = tempTree.Count;
                        // allocate child
                        tempTree.Add(0);
                        tempTree.Add(0);
                        tempTree.Add(0);
                        // write bvh2 clip node
                        stats.updateInner();
                        tempTree[nodeIndex + 0] = (axis << 30) | (1 << 29) | nextIndex;
                        tempTree[nodeIndex + 1] = ByteUtil.floatToRawIntBits(nodeL);
                        tempTree[nodeIndex + 2] = ByteUtil.floatToRawIntBits(nodeR);
                        // update nodebox and recurse
                        nodeBox[2 * axis + 0] = nodeL;
                        nodeBox[2 * axis + 1] = nodeR;
                        subdivide(left, rightOrig, tempTree, indices, gridBox, nodeBox, nextIndex, depth + 1, stats);
                        return;
                    }
                }
                // ensure we are making progress in the subdivision
                if (right == rightOrig)
                {
                    // all left
                    if (clipL <= split)
                    {
                        // keep looping on left half
                        gridBox[2 * axis + 1] = split;
                        prevClip = clipL;
                        wasLeft  = true;
                        continue;
                    }
                    if (prevAxis == axis && prevSplit == split)
                    {
                        // we are stuck here - create a leaf
                        stats.updateLeaf(depth, right - left + 1);
                        createNode(tempTree, nodeIndex, left, right);
                        return;
                    }
                    gridBox[2 * axis + 1] = split;
                    prevClip = float.NaN;
                }
                else if (left > right)
                {
                    // all right
                    right = rightOrig;
                    if (clipR >= split)
                    {
                        // keep looping on right half
                        gridBox[2 * axis + 0] = split;
                        prevClip = clipR;
                        wasLeft  = false;
                        continue;
                    }
                    if (prevAxis == axis && prevSplit == split)
                    {
                        // we are stuck here - create a leaf
                        stats.updateLeaf(depth, right - left + 1);
                        createNode(tempTree, nodeIndex, left, right);
                        return;
                    }
                    gridBox[2 * axis + 0] = split;
                    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 nextIndex = 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] = (prevAxis << 30) | nextIndex;
                            tempTree[nodeIndex + 1] = ByteUtil.floatToRawIntBits(prevClip);
                            tempTree[nodeIndex + 2] = ByteUtil.floatToRawIntBits(float.PositiveInfinity);
                        }
                        else
                        {
                            // create a node with a right child
                            // write leaf node
                            stats.updateInner();
                            tempTree[nodeIndex + 0] = (prevAxis << 30) | (nextIndex - 3);
                            tempTree[nodeIndex + 1] = ByteUtil.floatToRawIntBits(float.NegativeInfinity);
                            tempTree[nodeIndex + 2] = ByteUtil.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 = nextIndex;
                    }
                    break;
                }
            }
            // compute index of child nodes
            int nextIndex1 = 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
            {
                nextIndex1 -= 3;
            }
            // allocate right node
            if (nr > 0)
            {
                tempTree.Add(0);
                tempTree.Add(0);
                tempTree.Add(0);
            }
            // write leaf node
            stats.updateInner();
            tempTree[nodeIndex + 0] = (axis << 30) | nextIndex1;
            tempTree[nodeIndex + 1] = ByteUtil.floatToRawIntBits(clipL);
            tempTree[nodeIndex + 2] = ByteUtil.floatToRawIntBits(clipR);
            // prepare L/R child boxes
            float[] gridBoxL = new float[6];
            float[] gridBoxR = new float[6];
            float[] nodeBoxL = new float[6];
            float[] nodeBoxR = new float[6];
            for (int i = 0; i < 6; i++)
            {
                gridBoxL[i] = gridBoxR[i] = gridBox[i];
                nodeBoxL[i] = nodeBoxR[i] = nodeBox[i];
            }
            gridBoxL[2 * axis + 1] = gridBoxR[2 * axis] = split;
            nodeBoxL[2 * axis + 1] = clipL;
            nodeBoxR[2 * axis + 0] = clipR;
            // free memory
            gridBox = nodeBox = null;
            // recurse
            if (nl > 0)
            {
                subdivide(left, right, tempTree, indices, gridBoxL, nodeBoxL, nextIndex1, depth + 1, stats);
            }
            else
            {
                stats.updateLeaf(depth + 1, 0);
            }
            if (nr > 0)
            {
                subdivide(right + 1, rightOrig, tempTree, indices, gridBoxR, nodeBoxR, nextIndex1 + 3, depth + 1, stats);
            }
            else
            {
                stats.updateLeaf(depth + 1, 0);
            }
        }
예제 #2
0
        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;
                for (int i = 0; i < 3; i++)
                {
                    if (nodeBox.hi[i] < gridBox.lo[i] || nodeBox.lo[i] > gridBox.hi[i])
                    {
                        Log.outError(LogFilter.Server, "Reached tree area in error - discarding node with: {0} objects", right - left + 1);
                    }
                }
                // find longest axis
                axis  = (int)d.primaryAxis();
                split = 0.5f * (gridBox.lo[axis] + gridBox.hi[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;)
                {
                    int   obj    = (int)dat.indices[i];
                    float minb   = dat.primBound[obj].Lo[axis];
                    float maxb   = dat.primBound[obj].Hi[axis];
                    float center = (minb + maxb) * 0.5f;
                    if (center <= split)
                    {
                        // stay left
                        i++;
                        if (clipL < maxb)
                        {
                            clipL = maxb;
                        }
                    }
                    else
                    {
                        // move to the right most
                        int t = (int)dat.indices[i];
                        dat.indices[i]     = dat.indices[right];
                        dat.indices[right] = (uint)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[axis] && nodeR < nodeBox.hi[axis])
                {
                    float nodeBoxW = nodeBox.hi[axis] - nodeBox.lo[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[axis] = nodeL;
                        nodeBox.hi[axis] = nodeR;
                        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[axis] = split;
                        prevClip         = clipL;
                        wasLeft          = true;
                        continue;
                    }
                    gridBox.hi[axis] = split;
                    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[axis] = split;
                        prevClip         = clipR;
                        wasLeft          = false;
                        continue;
                    }
                    gridBox.lo[axis] = split;
                    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;

            gridBoxL.hi[axis] = gridBoxR.lo[axis] = split;
            nodeBoxL.hi[axis] = clipL;
            nodeBoxR.lo[axis] = clipR;
            // 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);
            }
        }
 private void subdivide(int left, int right, List<int> tempTree, int[] indices, float[] gridBox, float[] nodeBox, int nodeIndex, int depth, BuildStats stats)
 {
     if ((right - left + 1) <= 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
         float[] d = { gridBox[1] - gridBox[0], gridBox[3] - gridBox[2],
             gridBox[5] - gridBox[4] };
         if (d[0] < 0 || d[1] < 0 || d[2] < 0)
             throw new Exception("negative node extents");
         for (int i = 0; i < 3; i++)
         {
             if (nodeBox[2 * i + 1] < gridBox[2 * i] || nodeBox[2 * i] > gridBox[2 * i + 1])
             {
                 UI.printError(UI.Module.ACCEL, "Reached tree area in error - discarding node with: {0} objects", right - left + 1);
                 throw new Exception("invalid node overlap");
             }
         }
         // find longest axis
         if (d[0] > d[1] && d[0] > d[2])
             axis = 0;
         else if (d[1] > d[2])
             axis = 1;
         else
             axis = 2;
         split = 0.5f * (gridBox[2 * axis] + gridBox[2 * axis + 1]);
         // 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; )
         {
             int obj = indices[i];
             float minb = primitives.getPrimitiveBound(obj, 2 * axis + 0);
             float maxb = primitives.getPrimitiveBound(obj, 2 * axis + 1);
             float center = (minb + maxb) * 0.5f;
             if (center <= split)
             {
                 // stay left
                 i++;
                 if (clipL < maxb)
                     clipL = maxb;
             }
             else
             {
                 // move to the right most
                 int t = indices[i];
                 indices[i] = indices[right];
                 indices[right] = t;
                 right--;
                 if (clipR > minb)
                     clipR = minb;
             }
             if (nodeL > minb)
                 nodeL = minb;
             if (nodeR < maxb)
                 nodeR = maxb;
         }
         // check for empty space
         if (nodeL > nodeBox[2 * axis + 0] && nodeR < nodeBox[2 * axis + 1])
         {
             float nodeBoxW = nodeBox[2 * axis + 1] - nodeBox[2 * axis + 0];
             float nodeNewW = nodeR - nodeL;
             // node box is too big compare to space occupied by primitives?
             if (1.3f * nodeNewW < nodeBoxW)
             {
                 stats.updateBVH2();
                 int nextIndex = tempTree.Count;
                 // allocate child
                 tempTree.Add(0);
                 tempTree.Add(0);
                 tempTree.Add(0);
                 // write bvh2 clip node
                 stats.updateInner();
                 tempTree[nodeIndex + 0] = (axis << 30) | (1 << 29) | nextIndex;
                 tempTree[nodeIndex + 1] = ByteUtil.floatToRawIntBits(nodeL);
                 tempTree[nodeIndex + 2] = ByteUtil.floatToRawIntBits(nodeR);
                 // update nodebox and recurse
                 nodeBox[2 * axis + 0] = nodeL;
                 nodeBox[2 * axis + 1] = nodeR;
                 subdivide(left, rightOrig, tempTree, indices, gridBox, nodeBox, nextIndex, depth + 1, stats);
                 return;
             }
         }
         // ensure we are making progress in the subdivision
         if (right == rightOrig)
         {
             // all left
             if (clipL <= split)
             {
                 // keep looping on left half
                 gridBox[2 * axis + 1] = split;
                 prevClip = clipL;
                 wasLeft = true;
                 continue;
             }
             if (prevAxis == axis && prevSplit == split)
             {
                 // we are stuck here - create a leaf
                 stats.updateLeaf(depth, right - left + 1);
                 createNode(tempTree, nodeIndex, left, right);
                 return;
             }
             gridBox[2 * axis + 1] = split;
             prevClip = float.NaN;
         }
         else if (left > right)
         {
             // all right
             right = rightOrig;
             if (clipR >= split)
             {
                 // keep looping on right half
                 gridBox[2 * axis + 0] = split;
                 prevClip = clipR;
                 wasLeft = false;
                 continue;
             }
             if (prevAxis == axis && prevSplit == split)
             {
                 // we are stuck here - create a leaf
                 stats.updateLeaf(depth, right - left + 1);
                 createNode(tempTree, nodeIndex, left, right);
                 return;
             }
             gridBox[2 * axis + 0] = split;
             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 nextIndex = 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] = (prevAxis << 30) | nextIndex;
                     tempTree[nodeIndex + 1] = ByteUtil.floatToRawIntBits(prevClip);
                     tempTree[nodeIndex + 2] = ByteUtil.floatToRawIntBits(float.PositiveInfinity);
                 }
                 else
                 {
                     // create a node with a right child
                     // write leaf node
                     stats.updateInner();
                     tempTree[nodeIndex + 0] = (prevAxis << 30) | (nextIndex - 3);
                     tempTree[nodeIndex + 1] = ByteUtil.floatToRawIntBits(float.NegativeInfinity);
                     tempTree[nodeIndex + 2] = ByteUtil.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 = nextIndex;
             }
             break;
         }
     }
     // compute index of child nodes
     int nextIndex1 = 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
         nextIndex1 -= 3;
     // allocate right node
     if (nr > 0)
     {
         tempTree.Add(0);
         tempTree.Add(0);
         tempTree.Add(0);
     }
     // write leaf node
     stats.updateInner();
     tempTree[nodeIndex + 0] = (axis << 30) | nextIndex1;
     tempTree[nodeIndex + 1] = ByteUtil.floatToRawIntBits(clipL);
     tempTree[nodeIndex + 2] = ByteUtil.floatToRawIntBits(clipR);
     // prepare L/R child boxes
     float[] gridBoxL = new float[6];
     float[] gridBoxR = new float[6];
     float[] nodeBoxL = new float[6];
     float[] nodeBoxR = new float[6];
     for (int i = 0; i < 6; i++)
     {
         gridBoxL[i] = gridBoxR[i] = gridBox[i];
         nodeBoxL[i] = nodeBoxR[i] = nodeBox[i];
     }
     gridBoxL[2 * axis + 1] = gridBoxR[2 * axis] = split;
     nodeBoxL[2 * axis + 1] = clipL;
     nodeBoxR[2 * axis + 0] = clipR;
     // free memory
     gridBox = nodeBox = null;
     // recurse
     if (nl > 0)
         subdivide(left, right, tempTree, indices, gridBoxL, nodeBoxL, nextIndex1, depth + 1, stats);
     else
         stats.updateLeaf(depth + 1, 0);
     if (nr > 0)
         subdivide(right + 1, rightOrig, tempTree, indices, gridBoxR, nodeBoxR, nextIndex1 + 3, depth + 1, stats);
     else
         stats.updateLeaf(depth + 1, 0);
 }