Esempio n. 1
0
        internal void childExpanded(SSBVHNodeAdaptor <GO> nAda, ssBVHNode <GO> child)
        {
            bool expanded = false;

            if (child.box.Min.X < box.Min.X)
            {
                box.Min.X = child.box.Min.X; expanded = true;
            }
            if (child.box.Max.X > box.Max.X)
            {
                box.Max.X = child.box.Max.X; expanded = true;
            }
            if (child.box.Min.Y < box.Min.Y)
            {
                box.Min.Y = child.box.Min.Y; expanded = true;
            }
            if (child.box.Max.Y > box.Max.Y)
            {
                box.Max.Y = child.box.Max.Y; expanded = true;
            }
            if (child.box.Min.Z < box.Min.Z)
            {
                box.Min.Z = child.box.Min.Z; expanded = true;
            }
            if (child.box.Max.Z > box.Max.Z)
            {
                box.Max.Z = child.box.Max.Z; expanded = true;
            }

            if (expanded && parent != null)
            {
                parent.childExpanded(nAda, this);
            }
        }
Esempio n. 2
0
        internal float SAHofPair(ssBVHNode <GO> nodea, ssBVHNode <GO> nodeb)
        {
            SSAABB box = nodea.box;

            box.ExpandToFit(nodeb.box);
            return(SAH(ref box));
        }
Esempio n. 3
0
        internal void splitNode(SSBVHNodeAdaptor <GO> nAda)
        {
            // second, decide which axis to split on, and sort..
            List <GO> splitlist = gobjects;

            splitlist.ForEach(o => nAda.unmapObject(o));

            Axis splitAxis = pickSplitAxis();

            switch (splitAxis) // sort along the appropriate axis
            {
            case Axis.X:
                splitlist.Sort(delegate(GO go1, GO go2) { return(nAda.objectpos(go1).X.CompareTo(nAda.objectpos(go2).X)); });
                break;

            case Axis.Y:
                splitlist.Sort(delegate(GO go1, GO go2) { return(nAda.objectpos(go1).Y.CompareTo(nAda.objectpos(go2).Y)); });
                break;

            case Axis.Z:
                splitlist.Sort(delegate(GO go1, GO go2) { return(nAda.objectpos(go1).Z.CompareTo(nAda.objectpos(go2).Z)); });
                break;

            default: throw new NotImplementedException();
            }
            int center = (int)(splitlist.Count / 2);  // Find the center object in our current sub-list

            gobjects = null;

            // create the new left and right nodes...
            left  = new ssBVHNode <GO>(nAda.BVH, this, splitlist.GetRange(0, center), splitAxis, this.depth + 1);                        // Split the Hierarchy to the left
            right = new ssBVHNode <GO>(nAda.BVH, this, splitlist.GetRange(center, splitlist.Count - center), splitAxis, this.depth + 1); // Split the Hierarchy to the right
        }
Esempio n. 4
0
        private static Bounds_d BoundsOfPair(ssBVHNode <GO> nodea, ssBVHNode <GO> nodeb)
        {
            Bounds_d box = nodea.Bounds;

            box.ExpandToFit(nodeb.Bounds);
            return(box);
        }
Esempio n. 5
0
        internal SSAABB AABBofPair(ssBVHNode <GO> nodea, ssBVHNode <GO> nodeb)
        {
            SSAABB box = nodea.box;

            box.ExpandToFit(nodeb.box);
            return(box);
        }
Esempio n. 6
0
 internal ssBVHNode(ssBVH <GO> bvh)
 {
     gobjects        = new List <GO>();
     left            = right = null;
     parent          = null;
     this.nodeNumber = bvh.nodeCount++;
 }
Esempio n. 7
0
        private static void addObject_Pushdown(SSBVHNodeAdaptor <GO> nAda, ssBVHNode <GO> curNode, GO newOb)
        {
            var left  = curNode.Left;
            var right = curNode.Right;

            // merge and pushdown left and right as a new node..
            var mergedSubnode = new ssBVHNode <GO>(nAda.BVH)
            {
                Left             = left,
                Right            = right,
                Parent           = curNode,
                ContainedObjects = null
            };

            // we need to be an interior node... so null out our object list..
            left.Parent  = mergedSubnode;
            right.Parent = mergedSubnode;
            mergedSubnode.ChildRefit(nAda, false);

            // make new subnode for obj
            var newSubnode = new ssBVHNode <GO>(nAda.BVH);

            newSubnode.Parent           = curNode;
            newSubnode.ContainedObjects = new List <GO> {
                newOb
            };
            nAda.MapObjectToBvhLeaf(newOb, newSubnode);
            newSubnode.ComputeVolume(nAda);

            // make assignments..
            curNode.Left  = mergedSubnode;
            curNode.Right = newSubnode;
            curNode.SetDepth(nAda, curNode.Depth);             // propagate new depths to our children.
            curNode.ChildRefit(nAda);
        }
        internal static void addObject_Pushdown(SSBVHNodeAdaptor <GO> nAda, ssBVHNode <GO> curNode, GO newOb)
        {
            var left  = curNode.left;
            var right = curNode.right;

            // merge and pushdown left and right as a new node..
            var mergedSubnode = new ssBVHNode <GO>(nAda.BVH);

            mergedSubnode.left     = left;
            mergedSubnode.right    = right;
            mergedSubnode.parent   = curNode;
            mergedSubnode.gobjects = null; // we need to be an interior node... so null out our object list..
            left.parent            = mergedSubnode;
            right.parent           = mergedSubnode;
            mergedSubnode.childRefit(nAda, propagate: false);

            // make new subnode for obj
            var newSubnode = new ssBVHNode <GO>(nAda.BVH);

            newSubnode.parent   = curNode;
            newSubnode.gobjects = new List <GO> {
                newOb
            };
            nAda.mapObjectToBVHLeaf(newOb, newSubnode);
            newSubnode.computeVolume(nAda);

            // make assignments..
            curNode.left  = mergedSubnode;
            curNode.right = newSubnode;
            curNode.setDepth(nAda, curNode.depth); // propagate new depths to our children.
            curNode.childRefit(nAda);
        }
Esempio n. 9
0
        internal float SAH(ssBVHNode <GO> node)
        {
            float x_size = node.box.Max.X - node.box.Min.X;
            float y_size = node.box.Max.Y - node.box.Min.Y;
            float z_size = node.box.Max.Z - node.box.Min.Z;

            return(2.0f * ((x_size * y_size) + (x_size * z_size) + (y_size * z_size)));
        }
Esempio n. 10
0
        private static double SA(ssBVHNode <GO> node)
        {
            double x_size = node.Bounds.max.x - node.Bounds.min.x;
            double y_size = node.Bounds.max.y - node.Bounds.min.y;
            double z_size = node.Bounds.max.z - node.Bounds.min.z;

            return(2.0f * ((x_size * y_size) + (x_size * z_size) + (y_size * z_size)));
        }
Esempio n. 11
0
        public void mapObjectToBVHLeaf(SSObject obj, ssBVHNode <SSObject> leaf)
        {
            // this allows us to be notified when an object moves, so we can adjust the BVH
            obj.OnChanged += obj_OnChanged;

            // TODO: add a hook to handle SSObject deletion... (either a weakref GC notify, or OnDestroy)

            ssToLeafMap[obj] = leaf;
        }
Esempio n. 12
0
        internal ssBVHNode <GO> rootNode()
        {
            ssBVHNode <GO> cur = this;

            while (cur.parent != null)
            {
                cur = cur.parent;
            }
            return(cur);
        }
Esempio n. 13
0
 // internal functional traversal...
 private void _traverse(ssBVHNode <GO> curNode, NodeTest hitTest, List <ssBVHNode <GO> > hitlist)
 {
     if (curNode == null)
     {
         return;
     }
     if (hitTest(curNode.box))
     {
         hitlist.Add(curNode);
         _traverse(curNode.left, hitTest, hitlist);
         _traverse(curNode.right, hitTest, hitlist);
     }
 }
Esempio n. 14
0
        public void renderCells(ssBVHNode <SSObject> n, ref SSAABB parentbox, int depth)
        {
            float nudge = 0f;

            if (parentbox.Equals(n.box))
            {
                // attempt to nudge out of z-fighting
                nudge = 0.2f;
            }

            if (highlightNodes.Contains(n))
            {
                if (n.gobjects == null)
                {
                    GL.Color4(Color.FromArgb(255, 25, 25, 100));
                }
                else
                {
                    GL.Color4(Color.Green);
                }
            }
            else
            {
                if (n.gobjects == null)
                {
                    GL.Color4(Color.FromArgb(255, 20, 20, 20));
                }
                else
                {
                    GL.Color4(Color.DarkRed);
                }
            }

            Vector3 nudgeVect = new Vector3(nudge);
            Vector3 scale     = n.box.max - n.box.min - 2f * nudgeVect;
            Matrix4 mat       = Matrix4.CreateScale(scale) * Matrix4.CreateTranslation(n.box.min + nudgeVect);

            GL.PushMatrix();
            GL.MultMatrix(ref mat);
            ibo.DrawElements(PrimitiveType.Lines, false);
            GL.PopMatrix();

            if (n.right != null)
            {
                renderCells(n.right, ref n.box, depth: depth + 1);
            }
            if (n.left != null)
            {
                renderCells(n.left, ref n.box, depth: depth + 1);
            }
        }
Esempio n. 15
0
        private void RemoveLeaf(SSBVHNodeAdaptor <GO> nAda, ssBVHNode <GO> removeLeaf)
        {
            if (Left == null || Right == null)
            {
                throw new Exception("bad intermediate node");
            }

            ssBVHNode <GO> keepLeaf;

            if (removeLeaf == Left)
            {
                keepLeaf = Right;
            }
            else if (removeLeaf == Right)
            {
                keepLeaf = Left;
            }
            else
            {
                throw new Exception("removeLeaf doesn't match any leaf!");
            }

            // "become" the leaf we are keeping.
            Bounds           = keepLeaf.Bounds;
            Left             = keepLeaf.Left;
            Right            = keepLeaf.Right;
            ContainedObjects = keepLeaf.ContainedObjects;
            // clear the leaf..
            // keepLeaf.left = null; keepLeaf.right = null; keepLeaf.gobjects = null; keepLeaf.parent = null;

            if (ContainedObjects == null)
            {
                Left.Parent  = this;
                Right.Parent = this;                 // reassign child parents..
                SetDepth(nAda, Depth);               // this reassigns depth for our children
            }
            else
            {
                // map the objects we adopted to us...
                ContainedObjects.ForEach(
                    o => {
                    nAda.MapObjectToBvhLeaf(o, this);
                });
            }

            // propagate our new volume..
            if (Parent != null)
            {
                Parent.ChildRefit(nAda);
            }
        }
Esempio n. 16
0
        // internal functional traversal...
        private static void _query(ssBVHNode <T> curNode, NodeTest hitTest, ICollection <ssBVHNode <T> > hitlist)
        {
            if (curNode == null)
            {
                return;
            }

            if (hitTest(curNode.Bounds))
            {
                hitlist.Add(curNode);
                _query(curNode.Left, hitTest, hitlist);
                _query(curNode.Right, hitTest, hitlist);
            }
        }
Esempio n. 17
0
        /// <summary>
        /// initializes a BVH with a given nodeAdaptor, and object list.
        /// </summary>
        /// <param name="nodeAdaptor"></param>
        /// <param name="objects"></param>
        /// <param name="LEAF_OBJ_MAX">WARNING! currently this must be 1 to use dynamic BVH updates</param>
        public ssBVH(SSBVHNodeAdaptor <GO> nodeAdaptor, List <GO> objects, int LEAF_OBJ_MAX = 1)
        {
            this.LEAF_OBJ_MAX = LEAF_OBJ_MAX;
            nodeAdaptor.setBVH(this);
            this.nAda = nodeAdaptor;

            if (objects.Count > 0)
            {
                rootBVH = new ssBVHNode <GO>(this, objects);
            }
            else
            {
                rootBVH          = new ssBVHNode <GO>(this);
                rootBVH.gobjects = new List <GO>(); // it's a leaf, so give it an empty object list
            }
        }
        internal static void addObject(SSBVHNodeAdaptor <GO> nAda, ssBVHNode <GO> curNode, GO newOb, ref SSAABB newObBox, float newObSAH)
        {
            // 1. first we traverse the node looking for the best leaf
            while (curNode.gobjects == null)
            {
                // find the best way to add this object.. 3 options..
                // 1. send to left node  (L+N,R)
                // 2. send to right node (L,R+N)
                // 3. merge and pushdown left-and-right node (L+R,N)

                var left  = curNode.left;
                var right = curNode.right;

                float leftSAH               = SA(left);
                float rightSAH              = SA(right);
                float sendLeftSAH           = rightSAH + SA(left.box.ExpandedBy(newObBox)); // (L+N,R)
                float sendRightSAH          = leftSAH + SA(right.box.ExpandedBy(newObBox)); // (L,R+N)
                float mergedLeftAndRightSAH = SA(AABBofPair(left, right)) + newObSAH;       // (L+R,N)

                // Doing a merge-and-pushdown can be expensive, so we only do it if it's notably better
                const float MERGE_DISCOUNT = 0.3f;

                if (mergedLeftAndRightSAH < (Math.Min(sendLeftSAH, sendRightSAH)) * MERGE_DISCOUNT)
                {
                    addObject_Pushdown(nAda, curNode, newOb);
                    return;
                }
                else
                {
                    if (sendLeftSAH < sendRightSAH)
                    {
                        curNode = left;
                    }
                    else
                    {
                        curNode = right;
                    }
                }
            }

            // 2. then we add the object and map it to our leaf
            curNode.gobjects.Add(newOb);
            nAda.mapObjectToBVHLeaf(newOb, curNode);
            curNode.refitVolume(nAda);
            // split if necessary...
            curNode.splitIfNecessary(nAda);
        }
Esempio n. 19
0
        private static void ChildRefit(SSBVHNodeAdaptor <GO> nAda, ssBVHNode <GO> curNode, bool propagate = true)
        {
            do
            {
                ssBVHNode <GO> left  = curNode.Left;
                ssBVHNode <GO> right = curNode.Right;

                // start with the left box
                Bounds_d newBox = left.Bounds.ExpandedToFit(right.Bounds);

                // now set our box to the newly created box
                curNode.Bounds = newBox;

                // and walk up the tree
                curNode = curNode.Parent;
            } while (propagate && curNode != null);
        }
Esempio n. 20
0
        private static void AddObject(SSBVHNodeAdaptor <GO> nAda, ssBVHNode <GO> curNode, GO newOb, ref Bounds_d newObBox, double newObSAH)
        {
            // 1. first we traverse the node looking for the best leaf
            while (curNode.ContainedObjects == null)
            {
                // find the best way to add this object.. 3 options..
                // 1. send to left node  (L+N,R)
                // 2. send to right node (L,R+N)
                // 3. merge and pushdown left-and-right node (L+R,N)

                var left  = curNode.Left;
                var right = curNode.Right;

                double leftSAH               = SA(left);
                double rightSAH              = SA(right);
                double sendLeftSAH           = rightSAH + SA(left.Bounds.ExpandedToFit(newObBox));       // (L+N,R)
                double sendRightSAH          = leftSAH + SA(right.Bounds.ExpandedToFit(newObBox));       // (L,R+N)
                double mergedLeftAndRightSAH = SA(BoundsOfPair(left, right)) + newObSAH;                 // (L+R,N)

                // Doing a merge-and-pushdown can be expensive, so we only do it if it's notably better
                const double MERGE_DISCOUNT = 0.3f;

                if (mergedLeftAndRightSAH < (Math.Min(sendLeftSAH, sendRightSAH)) * MERGE_DISCOUNT)
                {
                    addObject_Pushdown(nAda, curNode, newOb);
                    return;
                }

                if (sendLeftSAH < sendRightSAH)
                {
                    curNode = left;
                }
                else
                {
                    curNode = right;
                }
            }

            // 2. then we add the object and map it to our leaf
            curNode.ContainedObjects.Add(newOb);
            nAda.MapObjectToBvhLeaf(newOb, curNode);
            curNode.RefitVolume(nAda);
            // split if necessary...
            curNode.SplitIfNecessary(nAda);
        }
        internal static void childRefit(SSBVHNodeAdaptor <GO> nAda, ssBVHNode <GO> curNode, bool propagate = true)
        {
            do
            {
                SSAABB         oldbox = curNode.box;
                ssBVHNode <GO> left   = curNode.left;
                ssBVHNode <GO> right  = curNode.right;

                // start with the left box
                SSAABB newBox = left.box;

                // expand any dimension bigger in the right node
                if (right.box.Min.X < newBox.Min.X)
                {
                    newBox.Min.X = right.box.Min.X;
                }
                if (right.box.Min.Y < newBox.Min.Y)
                {
                    newBox.Min.Y = right.box.Min.Y;
                }
                if (right.box.Min.Z < newBox.Min.Z)
                {
                    newBox.Min.Z = right.box.Min.Z;
                }

                if (right.box.Max.X > newBox.Max.X)
                {
                    newBox.Max.X = right.box.Max.X;
                }
                if (right.box.Max.Y > newBox.Max.Y)
                {
                    newBox.Max.Y = right.box.Max.Y;
                }
                if (right.box.Max.Z > newBox.Max.Z)
                {
                    newBox.Max.Z = right.box.Max.Z;
                }

                // now set our box to the newly created box
                curNode.box = newBox;

                // and walk up the tree
                curNode = curNode.parent;
            } while (propagate && curNode != null);
        }
Esempio n. 22
0
        /// <summary>
        /// initializes a BVH with a given nodeAdaptor, and object list.
        /// </summary>
        /// <param name="nodeAdaptor"></param>
        /// <param name="objects"></param>
        /// <param name="LEAF_OBJ_MAX">WARNING! currently this must be 1 to use dynamic BVH updates</param>
        public ssBVH(SSBVHNodeAdaptor <T> nodeAdaptor, List <T> objects, int LEAF_OBJ_MAX = 1)
        {
            this.LEAF_OBJ_MAX = LEAF_OBJ_MAX;
            nodeAdaptor.BVH   = this;
            nAda = nodeAdaptor;

            if (objects.Count > 0)
            {
                RootBVH = new ssBVHNode <T>(this, objects);
            }
            else
            {
                RootBVH = new ssBVHNode <T>(this)
                {
                    ContainedObjects = new List <T>()
                };                                                                                   // it's a leaf, so give it an empty object list
            }
        }
Esempio n. 23
0
        internal void removeLeaf(SSBVHNodeAdaptor <GO> nAda, ssBVHNode <GO> removeLeaf)
        {
            if (left == null || right == null)
            {
                throw new Exception("bad intermediate node");
            }
            ssBVHNode <GO> keepLeaf;

            if (removeLeaf == left)
            {
                keepLeaf = right;
            }
            else if (removeLeaf == right)
            {
                keepLeaf = left;
            }
            else
            {
                throw new Exception("removeLeaf doesn't match any leaf!");
            }

            // "become" the leaf we are keeping.
            box  = keepLeaf.box;
            left = keepLeaf.left; right = keepLeaf.right; gobjects = keepLeaf.gobjects;
            // clear the leaf..
            // keepLeaf.left = null; keepLeaf.right = null; keepLeaf.gobjects = null; keepLeaf.parent = null;

            if (gobjects == null)
            {
                left.parent = this; right.parent = this; // reassign child parents..
                this.setDepth(this.depth);               // this reassigns depth for our children
            }
            else
            {
                // map the objects we adopted to us...
                gobjects.ForEach(o => { nAda.mapObjectToBVHLeaf(o, this); });
            }

            // propagate our new volume..
            if (parent != null)
            {
                parent.childRefit(nAda);
            }
        }
        private ssBVHNode(ssBVH <GO> bvh, ssBVHNode <GO> lparent, List <GO> gobjectlist, Axis lastSplitAxis, int curdepth)
        {
            SSBVHNodeAdaptor <GO> nAda = bvh.nAda;

            this.nodeNumber = bvh.nodeCount++;

            this.parent = lparent; // save off the parent BVHGObj Node
            this.depth  = curdepth;

            if (bvh.maxDepth < curdepth)
            {
                bvh.maxDepth = curdepth;
            }

            // Early out check due to bad data
            // If the list is empty then we have no BVHGObj, or invalid parameters are passed in
            if (gobjectlist == null || gobjectlist.Count < 1)
            {
                throw new Exception("ssBVHNode constructed with invalid paramaters");
            }

            // Check if we’re at our LEAF node, and if so, save the objects and stop recursing.  Also store the min/max for the leaf node and update the parent appropriately
            if (gobjectlist.Count <= bvh.LEAF_OBJ_MAX)
            {
                // once we reach the leaf node, we must set prev/next to null to signify the end
                left  = null;
                right = null;
                // at the leaf node we store the remaining objects, so initialize a list
                gobjects = gobjectlist;
                gobjects.ForEach(o => nAda.mapObjectToBVHLeaf(o, this));
                computeVolume(nAda);
                splitIfNecessary(nAda);
            }
            else
            {
                // --------------------------------------------------------------------------------------------
                // if we have more than (bvh.LEAF_OBJECT_COUNT) objects, then compute the volume and split
                gobjects = gobjectlist;
                computeVolume(nAda);
                splitNode(nAda);
                childRefit(nAda, propagate: false);
            }
        }
Esempio n. 25
0
        private void SplitNode(SSBVHNodeAdaptor <GO> nAda)
        {
            // second, decide which axis to split on, and sort..
            List <GO> splitlist = ContainedObjects;

            splitlist.ForEach(nAda.UnmapObject);
            int center = splitlist.Count / 2;             // find the center object

            SplitAxisOpt <GO> bestSplit = eachAxis.Min(
                axis => {
                var orderedlist = new List <GO>(splitlist);
                switch (axis)
                {
                case Axis.X:
                    orderedlist.Sort((go1, go2) => nAda.GetObjectPosition(go1).x.CompareTo(nAda.GetObjectPosition(go2).x));
                    break;

                case Axis.Y:
                    orderedlist.Sort((go1, go2) => nAda.GetObjectPosition(go1).y.CompareTo(nAda.GetObjectPosition(go2).y));
                    break;

                case Axis.Z:
                    orderedlist.Sort((go1, go2) => nAda.GetObjectPosition(go1).z.CompareTo(nAda.GetObjectPosition(go2).z));
                    break;

                default:
                    throw new NotImplementedException("unknown split axis: " + axis.ToString());
                }

                var left_s  = orderedlist.GetRange(0, center);
                var right_s = orderedlist.GetRange(center, splitlist.Count - center);

                double SAH = SAofList(nAda, left_s) * left_s.Count + SAofList(nAda, right_s) * right_s.Count;
                return(new SplitAxisOpt <GO>(SAH, axis, left_s, right_s));
            });

            // perform the split
            ContainedObjects = null;
            Left             = new ssBVHNode <GO>(nAda.BVH, this, bestSplit.left, Depth + 1);  // Split the Hierarchy to the left
            Right            = new ssBVHNode <GO>(nAda.BVH, this, bestSplit.right, Depth + 1); // Split the Hierarchy to the right
        }
        // TODO: will need to calculate center of AABB
        internal void splitNode(SSBVHNodeAdaptor <GO> nAda)
        {
            // second, decide which axis to split on, and sort..
            List <GO> splitlist = gobjects;

            splitlist.ForEach(o => nAda.unmapObject(o));
            int center = (int)(splitlist.Count / 2); // find the center object

            SplitAxisOpt <GO> bestSplit = eachAxis.Min((axis) => {
                var orderedlist = new List <GO>(splitlist);
                switch (axis)
                {
                case Axis.X:
                    orderedlist.Sort(delegate(GO go1, GO go2) { return(nAda.boundingBox(go1).Center().X.CompareTo(nAda.boundingBox(go2).Center().X)); });
                    break;

                case Axis.Y:
                    orderedlist.Sort(delegate(GO go1, GO go2) { return(nAda.boundingBox(go1).Center().Y.CompareTo(nAda.boundingBox(go2).Center().Y)); });
                    break;

                case Axis.Z:
                    orderedlist.Sort(delegate(GO go1, GO go2) { return(nAda.boundingBox(go1).Center().Z.CompareTo(nAda.boundingBox(go2).Center().Z)); });
                    break;

                default:
                    throw new NotImplementedException("unknown split axis: " + axis.ToString());
                }

                var left_s  = orderedlist.GetRange(0, center);
                var right_s = orderedlist.GetRange(center, splitlist.Count - center);

                float SAH = SAofList(nAda, left_s) * left_s.Count + SAofList(nAda, right_s) * right_s.Count;
                return(new SplitAxisOpt <GO>(SAH, axis, left_s, right_s));
            });

            // perform the split
            gobjects   = null;
            this.left  = new ssBVHNode <GO>(nAda.BVH, this, bestSplit.left, bestSplit.axis, this.depth + 1);  // Split the Hierarchy to the left
            this.right = new ssBVHNode <GO>(nAda.BVH, this, bestSplit.right, bestSplit.axis, this.depth + 1); // Split the Hierarchy to the right
        }
Esempio n. 27
0
        internal void RemoveObject(SSBVHNodeAdaptor <GO> nAda, GO newOb)
        {
            if (ContainedObjects == null)
            {
                throw new Exception("removeObject() called on nonLeaf!");
            }

            nAda.UnmapObject(newOb);
            ContainedObjects.Remove(newOb);
            if (ContainedObjects.Count > 0)
            {
                RefitVolume(nAda);
            }
            else
            {
                // our leaf is empty, so collapse it if we are not the root...
                if (Parent != null)
                {
                    ContainedObjects = null;
                    Parent.RemoveLeaf(nAda, this);
                    Parent = null;
                }
            }
        }
Esempio n. 28
0
        /// <summary>
        /// tryRotate looks at all candidate rotations, and executes the rotation with the best resulting SAH (if any)
        /// </summary>
        /// <param name="bvh"></param>
        internal void TryRotate(ssBVH <GO> bvh)
        {
            SSBVHNodeAdaptor <GO> nAda = bvh.nAda;

            // if we are not a grandparent, then we can't rotate, so queue our parent and bail out
            if (Left.IsLeaf && Right.IsLeaf)
            {
                if (Parent != null)
                {
                    bvh.RefitNodes.Add(Parent);
                    return;
                }
            }

            // for each rotation, check that there are grandchildren as necessary (aka not a leaf)
            // then compute total SAH cost of our branches after the rotation.

            double mySA = SA(Left) + SA(Right);

            RotOpt bestRot = eachRot.Min(
                rot => {
                switch (rot)
                {
                case Rot.NONE: return(new RotOpt(mySA, Rot.NONE));

                // child to grandchild rotations
                case Rot.L_RL:
                    if (Right.IsLeaf)
                    {
                        return(new RotOpt(double.MaxValue, Rot.NONE));
                    }
                    else
                    {
                        return(new RotOpt(SA(Right.Left) + SA(BoundsOfPair(Left, Right.Right)), rot));
                    }

                case Rot.L_RR:
                    if (Right.IsLeaf)
                    {
                        return(new RotOpt(double.MaxValue, Rot.NONE));
                    }
                    else
                    {
                        return(new RotOpt(SA(Right.Right) + SA(BoundsOfPair(Left, Right.Left)), rot));
                    }

                case Rot.R_LL:
                    if (Left.IsLeaf)
                    {
                        return(new RotOpt(double.MaxValue, Rot.NONE));
                    }
                    else
                    {
                        return(new RotOpt(SA(BoundsOfPair(Right, Left.Right)) + SA(Left.Left), rot));
                    }

                case Rot.R_LR:
                    if (Left.IsLeaf)
                    {
                        return(new RotOpt(double.MaxValue, Rot.NONE));
                    }
                    else
                    {
                        return(new RotOpt(SA(BoundsOfPair(Right, Left.Left)) + SA(Left.Right), rot));
                    }

                // grandchild to grandchild rotations
                case Rot.LL_RR:
                    if (Left.IsLeaf || Right.IsLeaf)
                    {
                        return(new RotOpt(double.MaxValue, Rot.NONE));
                    }
                    else
                    {
                        return(new RotOpt(SA(BoundsOfPair(Right.Right, Left.Right)) + SA(BoundsOfPair(Right.Left, Left.Left)), rot));
                    }

                case Rot.LL_RL:
                    if (Left.IsLeaf || Right.IsLeaf)
                    {
                        return(new RotOpt(double.MaxValue, Rot.NONE));
                    }
                    else
                    {
                        return(new RotOpt(SA(BoundsOfPair(Right.Left, Left.Right)) + SA(BoundsOfPair(Left.Left, Right.Right)), rot));
                    }

                // unknown...
                default: throw new NotImplementedException("missing implementation for BVH Rotation SAH Computation .. " + rot.ToString());
                }
            });

            // perform the best rotation...
            if (bestRot.rot != Rot.NONE)
            {
                // if the best rotation is no-rotation... we check our parents anyhow..
                if (Parent != null)
                {
                    // but only do it some random percentage of the time.
                    if ((DateTime.Now.Ticks % 100) < 2)
                    {
                        bvh.RefitNodes.Add(Parent);
                    }
                }
            }
            else
            {
                if (Parent != null)
                {
                    bvh.RefitNodes.Add(Parent);
                }

                if (((mySA - bestRot.SAH) / mySA) < 0.3f)
                {
                    return;                     // the benefit is not worth the cost
                }

                Console.WriteLine("BVH swap {0} from {1} to {2}", bestRot.rot.ToString(), mySA, bestRot.SAH);

                // in order to swap we need to:
                //  1. swap the node locations
                //  2. update the depth (if child-to-grandchild)
                //  3. update the parent pointers
                //  4. refit the boundary box
                ssBVHNode <GO> swap = null;
                switch (bestRot.rot)
                {
                case Rot.NONE: break;

                // child to grandchild rotations
                case Rot.L_RL:
                    swap        = Left;
                    Left        = Right.Left;
                    Left.Parent = this;
                    Right.Left  = swap;
                    swap.Parent = Right;
                    Right.ChildRefit(nAda, propagate: false);
                    break;

                case Rot.L_RR:
                    swap        = Left;
                    Left        = Right.Right;
                    Left.Parent = this;
                    Right.Right = swap;
                    swap.Parent = Right;
                    Right.ChildRefit(nAda, propagate: false);
                    break;

                case Rot.R_LL:
                    swap         = Right;
                    Right        = Left.Left;
                    Right.Parent = this;
                    Left.Left    = swap;
                    swap.Parent  = Left;
                    Left.ChildRefit(nAda, propagate: false);
                    break;

                case Rot.R_LR:
                    swap         = Right;
                    Right        = Left.Right;
                    Right.Parent = this;
                    Left.Right   = swap;
                    swap.Parent  = Left;
                    Left.ChildRefit(nAda, propagate: false);
                    break;

                // grandchild to grandchild rotations
                case Rot.LL_RR:
                    swap             = Left.Left;
                    Left.Left        = Right.Right;
                    Right.Right      = swap;
                    Left.Left.Parent = Left;
                    swap.Parent      = Right;
                    Left.ChildRefit(nAda, propagate: false);
                    Right.ChildRefit(nAda, propagate: false);
                    break;

                case Rot.LL_RL:
                    swap             = Left.Left;
                    Left.Left        = Right.Left;
                    Right.Left       = swap;
                    Left.Left.Parent = Left;
                    swap.Parent      = Right;
                    Left.ChildRefit(nAda, propagate: false);
                    Right.ChildRefit(nAda, propagate: false);
                    break;

                // unknown...
                default: throw new NotImplementedException("missing implementation for BVH Rotation .. " + bestRot.rot);
                }

                // fix the depths if necessary....
                switch (bestRot.rot)
                {
                case Rot.L_RL:
                case Rot.L_RR:
                case Rot.R_LL:
                case Rot.R_LR:
                    SetDepth(nAda, Depth);
                    break;
                }
            }
        }
Esempio n. 29
0
 public void MapObjectToBvhLeaf(Shape shape, ssBVHNode <Shape> leaf)
 {
     _shapeToLeafMap[shape] = leaf;
 }
Esempio n. 30
0
 internal ssBVHNode(ssBVH <GO> bvh)
 {
     ContainedObjects = new List <GO>();
     Left             = Right = null;
     Parent           = null;
 }