Example #1
0
        /// <summary>
        /// Search in the BVH tree using a flexible "locator" object, which should return the
        /// "distance" of a BVH Node object.  Returns a list of results in increasing distance
        /// up to a relative bound and absolute maximum.
        /// </summary>
        /// <param name="distance_max">The maximum distance to look for.</param>
        /// <param name="relative_bound">Stop returning more items after 'relative_bound' times
        /// the first item's distance.</param>
        /// <param name="locator">A delegate, like Locate() but passed also the current 'distance_max'.</param>
        /// <returns>A list of instances of the concrete BVHNodeBase subclass.</returns>
        public List <BVHNodeBase> LocateList(float distance_max, float relative_bound, DistanceToNodeEx locator)
        {
            var output_list = new List <BVHNodeBase>();

            if (!(root is BVHNode))
            {
                if (root != null)
                {
                    float distance = locator(root, distance_max);
                    if (distance < distance_max)
                    {
                        output_list.Add(root);
                    }
                }
                return(output_list);
            }
            var         heapq      = new HeapQ <LocNext>();
            BVHNodeBase base_node  = root;
            float       distance_1 = 0;

            while (distance_1 < distance_max)
            {
                if (base_node is BVHNode)
                {
                    var node = (BVHNode)base_node;

                    float d_left = locator(node.left, distance_max);
                    if (d_left < distance_max)
                    {
                        if (!(node.left is BVHNode))
                        {
                            distance_max = Mathf.Min(distance_max, d_left * relative_bound);
                        }
                        heapq.Push(new LocNext(d_left, node.left));
                    }

                    float d_right = locator(node.right, distance_max);
                    if (d_right < distance_max)
                    {
                        if (!(node.right is BVHNode))
                        {
                            distance_max = Mathf.Min(distance_max, d_right * relative_bound);
                        }
                        heapq.Push(new LocNext(d_right, node.right));
                    }
                }
                else
                {
                    output_list.Add(base_node);
                }
                if (heapq.Empty)
                {
                    break;
                }
                LocNext next = heapq.Pop();
                distance_1 = next.distance;
                base_node  = next.node;
            }
            return(output_list);
        }
Example #2
0
        /// <summary>
        /// Search in the BVH tree using a flexible "locator" delegate, which should return the
        /// "distance" of a BVH Node object.
        /// </summary>
        /// <param name="distance">The maximum distance to look for.</param>
        /// <param name="locator">A delegate.  A typical implementation has got two cases: if
        /// given an instance of a concrete class that the caller knows about, it should return
        /// the distance to that; otherwise, it should return the distance to the bounding box.
        /// The present algorithm assumes that when a bounding box grows, the distance returned
        /// by "locator" decreases or stays constant.</param>
        /// <returns>A instance of the concrete BVHNodeBase subclass.</returns>
        public BVHNodeBase Locate(float distance_max, DistanceToNode locator)
        {
            if (!(root is BVHNode))
            {
                if (root != null)
                {
                    float distance = locator(root, distance_max);
                    if (distance < distance_max)
                    {
                        return(root);
                    }
                }
                return(null);
            }
            var         heapq     = new HeapQ <LocNext>();
            BVHNodeBase base_node = root;

            while (true)
            {
                if (base_node is BVHNode)
                {
                    var node = (BVHNode)base_node;

                    float d_left = locator(node.left, distance_max);
                    if (d_left < distance_max)
                    {
                        if (!(node.left is BVHNode))
                        {
                            distance_max = d_left;
                        }
                        heapq.Push(new LocNext(d_left, node.left));
                    }

                    float d_right = locator(node.right, distance_max);
                    if (d_right < distance_max)
                    {
                        if (!(node.right is BVHNode))
                        {
                            distance_max = d_right;
                        }
                        heapq.Push(new LocNext(d_right, node.right));
                    }
                }
                else
                {
                    return(base_node);
                }
                if (heapq.Empty)
                {
                    break;
                }
                LocNext next = heapq.Pop();
                base_node = next.node;
            }
            return(null);
        }
Example #3
0
        public void RemoveObject(BVHNodeBase old_object)
        {
            most_recent_node = null;

            if (old_object == root)
            {
                root = null;
                return;
            }

            BVHNodeBase keep;
            BVHNode     parent = old_object.bvh_parent;

            if (parent.left == old_object)
            {
                keep = parent.right;
            }
            else
            {
                keep = parent.left;
            }

            BVHNode grandparent = parent.bvh_parent;

            keep.bvh_parent = grandparent;
            if (grandparent == null)
            {
                root = keep;
            }
            else
            {
                if (grandparent.left == parent)
                {
                    grandparent.left = keep;
                }
                else
                {
                    grandparent.right = keep;
                }
                UpdateBounds(grandparent);
            }
        }
Example #4
0
        public void AddObject(BVHNodeBase new_object)
        {
            if (root == null)
            {
                new_object.bvh_parent = null;
                root = new_object;
                return;
            }

            // 0. start at 'most_recent_node', and go up as long as its
            // bounding box does not contain new_object's bounding box.
            BVHNodeBase walk = most_recent_node;

            if (walk == null)
            {
                walk = root;
            }
            else
            {
                while (walk != root)
                {
                    if (walk.bbox.Contains(new_object.bbox))
                    {
                        break;
                    }
                    walk = walk.bvh_parent;
                }
            }

            // 1. first we traverse the node looking for the best leaf
            float newObSAH = SA(new_object);

            while (walk is BVHNode)
            {
                var curNode = (BVHNode)walk;

                // 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)
                // we tend to avoid option 3 by the 0.3f factor below, because it means
                // that an unknown number of nodes get their depth increased.

                /* first a performance hack which also helps to randomly even out the
                 * two sides in case 'new_object' is between both the bounding box of
                 * 'left' and of 'right'
                 */
                var  right          = curNode.right;
                bool contains_right = right.bbox.Contains(new_object.bbox);
                var  left           = curNode.left;
                if (left.bbox.Contains(new_object.bbox))
                {
                    if (contains_right && _NextRandomBit())
                    {
                        walk = right;
                    }
                    else
                    {
                        walk = left;
                    }
                    continue;
                }
                else if (contains_right)
                {
                    walk = right;
                    continue;
                }

                float leftSAH               = SA(left);
                float rightSAH              = SA(right);
                float sendLeftSAH           = rightSAH + SA(left, new_object); // (L+N,R)
                float sendRightSAH          = leftSAH + SA(right, new_object); // (L,R+N)
                float mergedLeftAndRightSAH = SA(left, right) + newObSAH;      // (L+R,N)

                if (mergedLeftAndRightSAH < 0.3f * Mathf.Min(sendLeftSAH, sendRightSAH))
                {
                    break;
                }
                else
                {
                    if (sendLeftSAH < sendRightSAH)
                    {
                        walk = left;
                    }
                    else
                    {
                        walk = right;
                    }
                }
            }

            // 2. then we add the object and map it to our leaf
            BVHNode parent = walk.bvh_parent;

            most_recent_node = parent;
            var new_node = new BVHNode {
                bbox = walk.bbox, left = walk, right = new_object, bvh_parent = parent
            };

            walk.bvh_parent       = new_node;
            new_object.bvh_parent = new_node;

            if (parent == null)
            {
                Debug.Assert(walk == root);
                root = new_node;
            }
            else if (parent.left == walk)
            {
                parent.left = new_node;
            }
            else
            {
                parent.right = new_node;
            }

            UpdateBounds(new_node);
        }
Example #5
0
 internal LocNext(float distance, BVHNodeBase node)
 {
     this.distance = distance;
     this.node     = node;
 }
Example #6
0
 float SA(BVHNodeBase n1, BVHNodeBase n2)    /* return the SA() of the union */
 {
     return(SA(Vector3.Max(n1.bbox.max, n2.bbox.max) - Vector3.Min(n1.bbox.min, n2.bbox.min)));
 }
Example #7
0
 float SA(BVHNodeBase node)
 {
     return(SA(node.bbox.max - node.bbox.min));
 }