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);
        }
        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);
        }
Ejemplo n.º 3
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);
            }
        }
Ejemplo n.º 5
0
        internal void addObject(SSBVHNodeAdaptor <GO> nAda, GO newOb, ref SSAABB newObBox, float newObSAH)
        {
            if (gobjects != null)
            {
                // add the object and map it to our leaf
                gobjects.Add(newOb);
                nAda.mapObjectToBVHLeaf(newOb, this);
                refitVolume(nAda);
                // split if necessary...
                splitIfNecessary(nAda);
            }
            else
            {
                // 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)

                float leftSAH               = SAH(left);
                float rightSAH              = SAH(right);
                float sendLeftSAH           = rightSAH + SAH(left.box.ExpandedBy(newObBox)); // (L+N,R)
                float sendRightSAH          = leftSAH + SAH(right.box.ExpandedBy(newObBox)); // (L,R+N)
                float mergedLeftAndRightSAH = SAH(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)
                {
                    // merge and pushdown left and right as a new node..
                    var mSubnode = new ssBVHNode <GO>(nAda.BVH);
                    mSubnode.left     = left;
                    mSubnode.right    = right;
                    mSubnode.parent   = this;
                    mSubnode.gobjects = null; // we need to be an interior node... so null out our object list..
                    left.parent       = mSubnode;
                    right.parent      = mSubnode;
                    mSubnode.childRefit(nAda, recurse: false);

                    // make new subnode for obj
                    var nSubnode = new ssBVHNode <GO>(nAda.BVH);
                    nSubnode.parent   = this;
                    nSubnode.gobjects = new List <GO> {
                        newOb
                    };
                    nAda.mapObjectToBVHLeaf(newOb, nSubnode);
                    nSubnode.computeVolume(nAda);

                    // make assignments..
                    this.left  = mSubnode;
                    this.right = nSubnode;
                    this.setDepth(this.depth); // propagate new depths to our children.
                    this.childRefit(nAda);
                }
                else
                {
                    if (sendLeftSAH < sendRightSAH)
                    {
                        // send left
                        left.addObject(nAda, newOb, ref newObBox, newObSAH);
                    }
                    else
                    {
                        // send right
                        right.addObject(nAda, newOb, ref newObBox, newObSAH);
                    }
                }
            }
        }