Пример #1
0
        public Scene(IPrimitive accelerator, List<ILight> lights, IVolumeRegion volumeRegion)
        {
            Lights = lights;
            Aggregate = accelerator;
            VolumeRegion = volumeRegion;

            Bound = Aggregate.WorldBound;

            if (VolumeRegion != null)
                Bound = BoundingBox.Union (Bound, VolumeRegion.WorldBound);
        }
Пример #2
0
 public static BoundingBox Union(BoundingBox b, Point p)
 {
     BoundingBox ret = new BoundingBox (b);
     ret.pMin.x = Math.Min (b.pMin.x, p.x);
     ret.pMin.y = Math.Min (b.pMin.y, p.y);
     ret.pMin.z = Math.Min (b.pMin.z, p.z);
     ret.pMax.x = Math.Max (b.pMax.x, p.x);
     ret.pMax.y = Math.Max (b.pMax.y, p.y);
     ret.pMax.z = Math.Max (b.pMax.z, p.z);
     return ret;
 }
Пример #3
0
        public Grid(List<IPrimitive> primitives, bool refineImmediately)
        {
            if (refineImmediately)
            {
                foreach (IPrimitive primitive in primitives)
                {
                    primitive.FullyRefine (ref Primitives);
                }
            }
            else
                Primitives = primitives;

            foreach (IPrimitive primitive in Primitives)
                Bounds = BoundingBox.Union (Bounds, primitive.WorldBound);

            Vector delta = Bounds.pMax - Bounds.pMin;

            int maxAxis = Bounds.MaximumExtent;
            double invMaxWidth = 1.0 / delta[maxAxis];
            double cubeRoot = 3.0 * Math.Pow (Primitives.Count, 1.0 / 3.0);
            double voxelsPerUnitDistance = cubeRoot * invMaxWidth;

            for (int axis = 0; axis < 3; ++axis)
            {
                nVoxels[axis] = Util.RoundToInt (delta[axis] * voxelsPerUnitDistance);
                nVoxels[axis] = Util.Clamp (nVoxels[axis], 1, 64);
            }

            for (int axis = 0; axis < 3; ++axis)
            {
                Width[axis] = delta[axis] / nVoxels[axis];
                InvWidth[axis] = (Width[axis] == 0.0) ? 0.0 : 1.0 / Width[axis];
            }
            int nv = nVoxels[0] * nVoxels[1] * nVoxels[2];
            Voxels = new Voxel[nv];

            foreach (IPrimitive primitive in Primitives)
            {
                BoundingBox pb = primitive.WorldBound;
                int[] vmin = new int[3];
                int[] vmax = new int[3];

                for (int axis = 0; axis < 3; ++axis)
                {
                    vmin[axis] = PositionToVoxel (pb.pMin, axis);
                    vmax[axis] = PositionToVoxel (pb.pMax, axis);
                }

                for (int z = vmin[2]; z <= vmax[2]; ++z)
                {
                    for (int y = vmin[1]; y <= vmax[1]; ++y)
                    {
                        for (int x = vmin[0]; x <= vmax[0]; ++x)
                        {
                            int o = Offset (x, y, z);
                            if (Voxels[o] == null)
                            {
                                Voxels[o] = new Voxel (primitive);
                            }
                            else
                            {
                                Voxels[o].AddPrimitive (primitive);
                            }
                        }
                    }
                }
            }
        }
Пример #4
0
        /// <summary>
        ///     Builds the Kd-Tree
        /// </summary>
        /// <param name="nodeNum">
        ///     The current node index
        /// </param>
        /// <param name="nodeBounds">
        ///     The node's bounding box
        /// </param>
        /// <param name="allPrimBounds">
        ///     The primitive's bounding boxes
        /// </param>
        /// <param name="primNums">
        ///     Array of primitive indices
        /// </param>
        /// <param name="numberOfPrimitives">
        ///     Number of primitives to build from
        /// </param>
        /// <param name="depth">
        ///     The current recursion depth
        /// </param>
        /// <param name="edges">
        ///     Array of edges
        /// </param>
        /// <param name="prims0">
        ///
        /// </param>
        /// <param name="prims1">
        ///
        /// </param>
        /// <param name="badRefines">
        ///     Amount of bad refines
        /// </param>
        public void BuildTree(int nodeNum, BoundingBox nodeBounds, List<BoundingBox> allPrimBounds,
            int[] primNums, int numberOfPrimitives, int depth, List<BoundEdge>[] edges,
            int[] prims0, int[] prims1, int primIndex,
        int badRefines)
        {
            if (_nextFreeNode == _numberOfAllocatedNodes)
            {
                int nAlloc = Math.Max (2 * _numberOfAllocatedNodes, 512);
                KdAcceleratorNode[] n = new KdAcceleratorNode[nAlloc];

                if (_numberOfAllocatedNodes > 0)
                {
                    _nodes.CopyTo (n, 0);
                }
                _nodes = n;
                _numberOfAllocatedNodes = nAlloc;
            }
            ++_nextFreeNode;

            // Initialize leaf nodes if termination criteria is met
            if (numberOfPrimitives <= _maxPrimitives || depth == 0)
            {
                _nodes[nodeNum].InitLeaf (primNums, numberOfPrimitives);
                return;
            }

            // Initialize interior node and continue recursion.
            // Choose split axis position for interior node
            int bestAxis = -1, bestOffset = -1;
            double bestCost = double.PositiveInfinity;
            double oldCost = _isectCost * numberOfPrimitives;
            double totalSA = nodeBounds.SurfaceArea;
            double invTotalSA = 1.0 / totalSA;
            Vector d = nodeBounds.pMax - nodeBounds.pMin;

            int axis = nodeBounds.MaximumExtent;
            int retries = 0;

            while (true)
            {
                // Initialize edges for axis
                for (int i = 0; i < numberOfPrimitives; ++i)
                {
                    int pn = (int)primNums[i];
                    BoundingBox box = allPrimBounds[pn];
                    edges[axis][2 * i] = new BoundEdge (box.pMin[axis], pn, true);
                    edges[axis][2 * i + 1] = new BoundEdge (box.pMax[axis], pn, false);
                }

                edges[axis].Sort (0, 2 * numberOfPrimitives, comparer);

                // Compute cost of all splits for axis to find best
                int nBelow = 0, nAbove = numberOfPrimitives;

                for (int i = 0; i < 2 * numberOfPrimitives; ++i)
                {
                    if (edges[axis][i].Type == BoundEdge.EdgeType.End)
                        --nAbove;
                    double edget = edges[axis][i].t;

                    if (edget > nodeBounds.pMin[axis] && edget < nodeBounds.pMax[axis])
                    {
                        int otherAxis0 = (axis + 1) % 3, otherAxis1 = (axis + 2) % 3;

                        double belowSA = 2 * (d[otherAxis0] * d[otherAxis1] + (edget - nodeBounds.pMin[axis]) * (d[otherAxis0] + d[otherAxis1]));
                        double aboveSA = 2 * (d[otherAxis0] * d[otherAxis1] + (nodeBounds.pMax[axis] - edget) * (d[otherAxis0] + d[otherAxis1]));
                        double pBelow = belowSA * invTotalSA;
                        double pAbove = aboveSA * invTotalSA;
                        double eb = (nAbove == 0 || nBelow == 0) ? _emptyBonus : 0.0;
                        double cost = _traversalCost + _isectCost * (1.0 - eb) * (pBelow * nBelow + pAbove * nAbove);

                        // Update best split if this is the lowest so far
                        if (cost < bestCost)
                        {
                            bestCost = cost;
                            bestAxis = axis;
                            bestOffset = i;
                        }
                    }

                    if (edges[axis][i].Type == BoundEdge.EdgeType.Start)
                        ++nBelow;
                }

                // Create leaf if no good splits were found
                if (bestAxis == -1 && retries < 2)
                {
                    ++retries;
                    axis = (axis + 1) % 3;
                    continue;
                }
                break;
            }

            if (bestCost > oldCost)
                ++badRefines;

            if ((bestCost > 4.0 * oldCost && numberOfPrimitives < 16) || bestAxis == -1 || badRefines == 3)
            {
                _nodes[nodeNum].InitLeaf (primNums, numberOfPrimitives);
                return;
            }

            // Classify primitives with respect to split
            int n0 = 0, n1 = 0;
            for (int i = 0; i < bestOffset; ++i)
                if (edges[bestAxis][i].Type == BoundEdge.EdgeType.Start)
                    prims0[n0++] = edges[bestAxis][i].PrimitiveNumber;
            for (int i = bestOffset + 1; i < 2 * numberOfPrimitives; ++i)
                if (edges[bestAxis][i].Type == BoundEdge.EdgeType.End)
                    prims1[primIndex + n1++] = edges[bestAxis][i].PrimitiveNumber;

            // Recursively initialize child nodes
            double tsplit = edges[bestAxis][bestOffset].t;
            BoundingBox bounds0 = new BoundingBox (nodeBounds), bounds1 = new BoundingBox(nodeBounds);
            bounds0.pMax[bestAxis] = bounds1.pMin[bestAxis] = tsplit;

            BuildTree (nodeNum + 1, bounds0, allPrimBounds, prims0, n0, depth - 1, edges, prims0, prims1, numberOfPrimitives + primIndex, badRefines);
            int aboveChild = _nextFreeNode;
            _nodes[nodeNum].InitInterior (bestAxis, aboveChild, tsplit);
            BuildTree (aboveChild, bounds1, allPrimBounds, prims1, n1, depth - 1, edges, prims0, prims1, numberOfPrimitives + primIndex, badRefines);
        }
Пример #5
0
        /// <summary>
        ///     Creates a new KdTree
        /// </summary>
        /// <param name="p">
        ///     List of primitives to build the kd-Tree from
        /// </param>
        /// <param name="isectCost">
        ///     Cost for an intersection
        /// </param>
        /// <param name="traversalCost">
        ///     Cost for traversing along edges
        /// </param>
        /// <param name="emptyBonus">
        ///     Bonus for empty leafs
        /// </param>
        /// <param name="maxPrimitives">
        ///     Maximum amount of primitives per leaf
        /// </param>
        /// <param name="maxDepth">
        ///     Maximum recursion depth
        /// </param>
        public KdTree(List<IPrimitive> p, int isectCost, int traversalCost, double emptyBonus, int maxPrimitives, int maxDepth)
        {
            _isectCost = isectCost;
            _traversalCost = traversalCost;
            _emptyBonus = emptyBonus;
            _maxPrimitives = maxPrimitives;
            _maxDepth = maxDepth;

            Console.WriteLine ("    - Refining {0} primitives...", p.Count);
            foreach (IPrimitive primitive in p)
                primitive.FullyRefine (ref _primitives);
            Console.WriteLine ("    - Refined into {0} primitives", _primitives.Count);

            // Build kd-Tree
            _nextFreeNode = _numberOfAllocatedNodes = 0;
            if (_maxDepth <= 0)
                _maxDepth = Util.RoundToInt (8 + 1.3 * Util.Log2Int ((double)_primitives.Count));

            // Compute bounds for kd-Tree generation
            List<BoundingBox> primitiveBounds = new List<BoundingBox> ();
            primitiveBounds.Capacity = _primitives.Count;

            foreach (IPrimitive primitive in _primitives)
            {
                BoundingBox b = primitive.WorldBound;
                _bounds = BoundingBox.Union (_bounds, b);
                primitiveBounds.Add (b);
            }
            Console.WriteLine ("    - KdTree Volume: {0}", _bounds.Volume);

            // Allocate working memory for kd-Tree construction
            List<BoundEdge>[] edges = new List<BoundEdge>[3];
            edges[0] = new List<BoundEdge> ();
            edges[1] = new List<BoundEdge> ();
            edges[2] = new List<BoundEdge> ();

            for (int i = 0; i < 3; ++i)
            {
                edges[i].Capacity = 2 * _primitives.Count;
                for (int j = 0; j < 2 * _primitives.Count; ++j)
                    edges[i].Add (null);
            }

            int[] prims0 = new int[_primitives.Count];
            int[] prims1 = new int[(_maxDepth + 1) * _primitives.Count];

            // Initialize primNums for kd-Tree construction
            int[] primNums = new int[_primitives.Count];

            for (int i = 0; i < _primitives.Count; ++i)
                primNums[i] = i;

            // Start recursive construction of kd-Tree
            Console.WriteLine ("    - Building KdTree for {0} primitives...", _primitives.Count);
            BuildTree (0, _bounds, primitiveBounds, primNums, _primitives.Count, _maxDepth, edges, prims0, prims1, 0, 0);
            Console.WriteLine ("    - Created KdTree with {0} nodes and {1} leafs.", NumberOfTotalNodes, NumberOfTotalLeafs);
        }
Пример #6
0
 public static BoundingBox Union(BoundingBox b, BoundingBox b2)
 {
     BoundingBox ret = new BoundingBox (b);
     ret.pMin.x = Math.Min (b.pMin.x, b2.pMin.x);
     ret.pMin.y = Math.Min (b.pMin.y, b2.pMin.y);
     ret.pMin.z = Math.Min (b.pMin.z, b2.pMin.z);
     ret.pMax.x = Math.Max (b.pMax.x, b2.pMax.x);
     ret.pMax.y = Math.Max (b.pMax.y, b2.pMax.y);
     ret.pMax.z = Math.Max (b.pMax.z, b2.pMax.z);
     return ret;
 }
Пример #7
0
 public BoundingBox(BoundingBox b)
 {
     pMin = new Point (b.pMin);
     pMax = new Point (b.pMax);
 }
Пример #8
0
 public bool Overlaps(BoundingBox b)
 {
     bool x = (pMax.x >= b.pMin.x) && (pMin.x <= b.pMax.x);
     bool y = (pMax.y >= b.pMin.y) && (pMin.y <= b.pMax.y);
     bool z = (pMax.z >= b.pMin.z) && (pMin.z <= b.pMax.z);
     return (x && y && z);
 }