/// <summary>
        /// This method will recalculate the node's center and radius
        /// so that it encapsulates all children. This is a recursive
        /// call which propagates up the hierarchy towards the root.
        /// </summary>
        public void EncapsulateChildrenBottomUp()
        {
            // Nothing to do if the node doesn't have any children
            if (NumChildren != 0)
            {
                // First, we will calculate the new sphere center as the average
                // of all child node centers.
                Vector3 centerSum = Vector3.zero;
                foreach (var child in _children)
                {
                    centerSum += child.Center;
                }
                Center = centerSum * (1.0f / NumChildren);

                // Now we will calculate the radius which the node must have so that
                // it can encapsulate all its children.
                float maxRadius = float.MinValue;
                foreach (var child in _children)
                {
                    float distToExitPt = (child.Center - _sphere.Center).magnitude + child.Radius;
                    if (distToExitPt > maxRadius)
                    {
                        maxRadius = distToExitPt;
                    }
                }
                Radius = maxRadius;

                // If we have a parent, move up the hierarchy
                if (_parent != null)
                {
                    _parent.EncapsulateChildrenBottomUp();
                }
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Removes the specified node from the tree. The client code should only
        /// ever call this method on nodes returned from 'AddNode'.
        /// </summary>
        public void RemoveNode(SphereTreeNode <T> node)
        {
            // The root node can never be removed
            if (node.IsFlagBitSet(BVHNodeFlags.Root))
            {
                return;
            }

            // Keep moving up the hierarchy and remove all nodes which don't
            // have any child nodes any more. There's no point in keeping these
            // around as they're nothing but noise inside the tree.
            SphereTreeNode <T> parent = node.Parent;

            node.SetParent(null);
            while (parent != null && parent.NumChildren == 0 && !parent.IsFlagBitSet(BVHNodeFlags.Root))
            {
                SphereTreeNode <T> newParent = parent.Parent;
                parent.SetParent(null);
                parent = newParent;
            }

            // We have been removing nodes, so we need to make sure that the parent
            // at which we stopped the removal process has its volume recalculated.
            parent.EncapsulateChildrenBottomUp();
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Must be called whenever a node's bounding sphere has changed.
        /// </summary>
        public void OnNodeSphereUpdated(SphereTreeNode <T> node)
        {
            // Just make sure this is a terminal node. Otherwise, ignore.
            if (!node.IsFlagBitSet(BVHNodeFlags.Terminal))
            {
                return;
            }

            // Check if the node is now outside of its parent
            if (node.IsOutsideParent())
            {
                // The node is outside of its parent. In this case, the first step
                // is to detach it from its parent.
                SphereTreeNode <T> parent = node.Parent;
                node.SetParent(null);

                // Now if the parent no longer has any children, we remove it from the
                // tree. Otherwise, we make sure it properly encapsulates its children.
                if (parent.NumChildren == 0)
                {
                    RemoveNode(parent);
                }
                else
                {
                    parent.EncapsulateChildrenBottomUp();
                }

                // The node needs to be reintegrated inside the tree
                IntegrateNodeRecurse(node, _root);
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Integrates 'node' inside the tree. This is a recursive method which will
        /// search for the best place where to place this node inside the tree.
        /// </summary>
        /// <param name="parent">
        /// Keeps track of the current parent node we are processing., Allow us to keep
        /// going down the tree hierarchy.
        /// </param>
        private void IntegrateNodeRecurse(SphereTreeNode <T> node, SphereTreeNode <T> parent)
        {
            // Are we dealing with a terminal node?
            if (!parent.IsFlagBitSet(BVHNodeFlags.Terminal))
            {
                // This is not a terminal node. First thing to do is check if this node has
                // room for one more child. If it does, we add the node here. Otherwise, we
                // keep searching.
                if (parent.NumChildren < _numChildrenPerNode)
                {
                    node.SetFlagsBits(BVHNodeFlags.Terminal);
                    node.SetParent(parent);
                    parent.EncapsulateChildrenBottomUp();
                }
                else
                {
                    // Find the child closest to 'node' and recurse down that path
                    SphereTreeNode <T> closestChild = parent.ClosestChild(node);
                    if (closestChild != null)
                    {
                        IntegrateNodeRecurse(node, closestChild);
                    }
                }
            }
            else
            {
                // We have reached a terminal node. We have no choice but to create a new non-terminal
                // node to take the place of the terminal one and then attach the integration node and
                // the old terminal node as children of this new node.
                SphereTreeNode <T> newParentNode = new SphereTreeNode <T>(default(T), parent.Sphere);
                newParentNode.SetParent(parent.Parent);
                parent.SetParent(newParentNode);

                node.SetParent(newParentNode);
                node.SetFlagsBits(BVHNodeFlags.Terminal);
                newParentNode.EncapsulateChildrenBottomUp();
            }
        }