Example #1
0
 public void Encapsulate(Aabb other)
 {
     min = Vector4.Min(min, other.min);
     max = Vector4.Max(max, other.max);
 }
Example #2
0
        public static BIHNode[] Build(ref IBounded[] elements, int maxDepth = 10, float maxOverlap = 0.7f)
        {
            List <BIHNode> nodes = new List <BIHNode> {
                new BIHNode(0, elements.Length)
            };

            // auxiliar variables to keep track of current tree depth:
            int depth            = 0;
            int nodesToNextLevel = 1;

            var queue = new Queue <int>();

            queue.Enqueue(0);

            while (queue.Count > 0)
            {
                // get current node:
                int index = queue.Dequeue();
                var node  = nodes[index];

                // if this node contains enough elements, split it:
                if (node.count > 2)
                {
                    int start = node.start;
                    int end   = start + (node.count - 1);

                    // calculate bounding box of all elements:
                    Aabb b = elements[start].GetBounds();
                    for (int k = start + 1; k <= end; ++k)
                    {
                        b.Encapsulate(elements[k].GetBounds());
                    }

                    // determine split axis (longest one):
                    Vector3 size = b.size;
                    int     axis = node.axis = (size.x > size.y) ?
                                               (size.x > size.z ? 0 : 2) :
                                               (size.y > size.z ? 1 : 2);

                    // place split plane at half the longest axis:
                    float pivot = b.min[axis] + size[axis] * 0.5f;

                    // sort elements using the split plane (Hoare's partition algorithm):
                    int  i = start - 1;
                    int  j = end + 1;
                    Aabb bi, bj;
                    while (true)
                    {
                        // iterate over left elements, while they're smaller than the pivot.
                        do
                        {
                            bi = elements[++i].GetBounds();
                            if (bi.center[axis] < pivot)
                            {
                                node.min = Mathf.Max(node.min, bi.max[axis]);
                            }
                        } while (bi.center[axis] < pivot);

                        // iterate over right elements, while they're larger than the pivot.
                        do
                        {
                            bj = elements[--j].GetBounds();
                            if (bj.center[axis] >= pivot)
                            {
                                node.max = Mathf.Min(node.max, bj.min[axis]);
                            }
                        } while (bj.center[axis] >= pivot);

                        // if element i is larger than the pivot, j smaller than the pivot, swap them.
                        if (i < j)
                        {
                            ObiUtils.Swap(ref elements[i], ref elements[j]);
                            node.min = Mathf.Max(node.min, bj.max[axis]);
                            node.max = Mathf.Min(node.max, bi.min[axis]);
                        }
                        else
                        {
                            break;
                        }
                    }

                    // create two child nodes:
                    var minChild = new BIHNode(start, j - start + 1);
                    var maxChild = new BIHNode(j + 1, end - j);

                    // calculate child overlap:
                    float overlap = size[axis] > 0 ? Mathf.Max(node.min - node.max, 0) / size[axis] : 1;

                    // guard against cases where all elements are on one side of the split plane,
                    // due to all having the same or very similar bounds as the entire group.
                    if (overlap <= maxOverlap && minChild.count > 0 && maxChild.count > 0)
                    {
                        node.firstChild = nodes.Count;
                        nodes[index]    = node;

                        queue.Enqueue(nodes.Count);
                        queue.Enqueue(nodes.Count + 1);

                        // append child nodes to list:
                        nodes.Add(minChild);
                        nodes.Add(maxChild);
                    }

                    // keep track of current depth:
                    if (--nodesToNextLevel == 0)
                    {
                        depth++;
                        if (depth >= maxDepth)
                        {
                            return(nodes.ToArray());
                        }
                        nodesToNextLevel = queue.Count;
                    }
                }
            }
            return(nodes.ToArray());
        }