Пример #1
0
        internal override bool TryToInsert(LeafNode node, out Node treeNode)
        {
            InternalNode newTreeNode = InternalNode.nodePool.Take();

            BoundingBox.CreateMerged(ref BoundingBox, ref node.BoundingBox, out newTreeNode.BoundingBox);
            Vector3 offset;

            Vector3.Subtract(ref newTreeNode.BoundingBox.Max, ref newTreeNode.BoundingBox.Min, out offset);
            newTreeNode.currentVolume = offset.X * offset.Y * offset.Z;
            newTreeNode.childA        = this;
            newTreeNode.childB        = node;
            treeNode = newTreeNode;
            return(true);
        }
Пример #2
0
        /// <summary>
        /// Adds an entry to the hierarchy.
        /// </summary>
        /// <param name="entry">Entry to add.</param>
        public override void Add(BroadPhaseEntry entry)
        {
            base.Add(entry);
            //Entities do not set up their own bounding box before getting stuck in here.  If they're all zeroed out, the tree will be horrible.
            Vector3 offset;

            Vector3.Subtract(ref entry.boundingBox.Max, ref entry.boundingBox.Min, out offset);
            if (offset.X * offset.Y * offset.Z == 0)
            {
                entry.UpdateBoundingBox();
            }

            //Could buffer additions to get a better construction in the tree.
            LeafNode node = leafNodes.Take();

            node.Initialize(entry);
            if (root == null)
            {
                //Empty tree.  This is the first and only node.
                root = node;
            }
            else
            {
                if (root.IsLeaf) //Root is alone.
                {
                    root.TryToInsert(node, out root);
                }
                else
                {
                    BoundingBox.CreateMerged(ref node.BoundingBox, ref root.BoundingBox, out root.BoundingBox);
                    InternalNode internalNode = (InternalNode)root;
                    Vector3.Subtract(ref root.BoundingBox.Max, ref root.BoundingBox.Min, out offset);
                    internalNode.currentVolume = offset.X * offset.Y * offset.Z;
                    //internalNode.maximumVolume = internalNode.currentVolume * InternalNode.MaximumVolumeScale;
                    //The caller is responsible for the merge.
                    Node treeNode = root;
                    while (!treeNode.TryToInsert(node, out treeNode))
                    {
                        ; //TryToInsert returns the next node, if any, and updates node bounding box.
                    }
                }
            }
        }
Пример #3
0
        private void Reconstruct(RawList <LeafNode> leafNodes, int begin, int end)
        {
            //It is known that we have 2 children; this is safe.
            //This is because this is only an internal node if the parent figured out it involved more than 2 leaf nodes, OR
            //this node was the initiator of the revalidation (in which case, it was an internal node with 2+ children).
            BoundingBox.CreateMerged(ref leafNodes.Elements[begin].BoundingBox,
                                     ref leafNodes.Elements[begin + 1].BoundingBox, out BoundingBox);
            for (int i = begin + 2; i < end; i++)
            {
                BoundingBox.CreateMerged(ref BoundingBox, ref leafNodes.Elements[i].BoundingBox, out BoundingBox);
            }

            Vector3 offset;

            Vector3.Subtract(ref BoundingBox.Max, ref BoundingBox.Min, out offset);
            currentVolume = offset.X * offset.Y * offset.Z;
            maximumVolume = currentVolume * MaximumVolumeScale;

            //Pick an axis and sort along it.
            if (offset.X > offset.Y && offset.X > offset.Z)
            //Maximum variance axis is X.
            {
                Array.Sort(leafNodes.Elements, begin, end - begin, xComparer);
            }
            else if (offset.Y > offset.Z)
            //Maximum variance axis is Y.
            {
                Array.Sort(leafNodes.Elements, begin, end - begin, yComparer);
            }
            else
            //Maximum variance axis is Z.
            {
                Array.Sort(leafNodes.Elements, begin, end - begin, zComparer);
            }

            //Find the median index.
            int median = (begin + end) / 2;

            if (median - begin >= 2)
            {
                //There are 2 or more leaf nodes remaining in the first half.  The next childA will be an internal node.
                InternalNode newChildA = nodePool.Take();
                newChildA.Reconstruct(leafNodes, begin, median);
                childA = newChildA;
            }
            else
            {
                //There is only 1 leaf node remaining in this half.  It's a leaf node.
                childA = leafNodes.Elements[begin];
            }

            if (end - median >= 2)
            {
                //There are 2 or more leaf nodes remaining in the second half.  The next childB will be an internal node.
                InternalNode newChildB = nodePool.Take();
                newChildB.Reconstruct(leafNodes, median, end);
                childB = newChildB;
            }
            else
            {
                //There is only 1 leaf node remaining in this half.  It's a leaf node.
                childB = leafNodes.Elements[median];
            }
        }
Пример #4
0
        internal override bool TryToInsert(LeafNode node, out Node treeNode)
        {
            //Since we are an internal node, we know we have two children.
            //Regardless of what kind of nodes they are, figure out which would be a better choice to merge the new node with.

            //Use the path which produces the smallest 'volume.'
            BoundingBox mergedA, mergedB;

            BoundingBox.CreateMerged(ref childA.BoundingBox, ref node.BoundingBox, out mergedA);
            BoundingBox.CreateMerged(ref childB.BoundingBox, ref node.BoundingBox, out mergedB);

            Vector3 offset;
            float   originalAVolume, originalBVolume;

            Vector3.Subtract(ref childA.BoundingBox.Max, ref childA.BoundingBox.Min, out offset);
            originalAVolume = offset.X * offset.Y * offset.Z;
            Vector3.Subtract(ref childB.BoundingBox.Max, ref childB.BoundingBox.Min, out offset);
            originalBVolume = offset.X * offset.Y * offset.Z;

            float mergedAVolume, mergedBVolume;

            Vector3.Subtract(ref mergedA.Max, ref mergedA.Min, out offset);
            mergedAVolume = offset.X * offset.Y * offset.Z;
            Vector3.Subtract(ref mergedB.Max, ref mergedB.Min, out offset);
            mergedBVolume = offset.X * offset.Y * offset.Z;

            //Could use factor increase or absolute difference
            if (mergedAVolume - originalAVolume < mergedBVolume - originalBVolume)
            {
                //merging A produces a better result.
                if (childA.IsLeaf)
                {
                    InternalNode newChildA = nodePool.Take();
                    newChildA.BoundingBox   = mergedA;
                    newChildA.childA        = childA;
                    newChildA.childB        = node;
                    newChildA.currentVolume = mergedAVolume;
                    childA   = newChildA;
                    treeNode = null;
                    return(true);
                }

                childA.BoundingBox = mergedA;
                InternalNode internalNode = (InternalNode)childA;
                internalNode.currentVolume = mergedAVolume;
                treeNode = childA;
                return(false);
            }

            //merging B produces a better result.
            if (childB.IsLeaf)
            {
                //Target is a leaf! Return.
                InternalNode newChildB = nodePool.Take();
                newChildB.BoundingBox   = mergedB;
                newChildB.childA        = node;
                newChildB.childB        = childB;
                newChildB.currentVolume = mergedBVolume;
                childB   = newChildB;
                treeNode = null;
                return(true);
            }

            {
                childB.BoundingBox = mergedB;
                treeNode           = childB;
                InternalNode internalNode = (InternalNode)childB;
                internalNode.currentVolume = mergedBVolume;
                return(false);
            }
        }