public void LocateSelect(SelectNode locator) { if (!(root is BVHNode)) { if (root != null) { locator(root); } return; } var stack = new Stack <BVHNode>(); BVHNode node = (BVHNode)root; while (true) { bool right = locator(node.right); bool left = locator(node.left); if (left) { if (right) { stack.Push((BVHNode)node.right); } node = (BVHNode)node.left; } else { if (right) { node = (BVHNode)node.right; } else { if (stack.Count == 0) { break; } node = stack.Pop(); } } } }
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); } }
void UpdateBounds(BVHNode node) { while (true) { Vector3 min = Vector3.Min(node.left.bbox.min, node.right.bbox.min); Vector3 max = Vector3.Max(node.left.bbox.max, node.right.bbox.max); if (min != node.bbox.min || max != node.bbox.max) { node.bbox = new BBox(min, max); node = node.bvh_parent; if (node == null) { break; } } else { break; } } }
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); }