public void Encapsulate(Aabb other) { min = Vector4.Min(min, other.min); max = Vector4.Max(max, other.max); }
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()); }