private static void addObject_Pushdown(SSBVHNodeAdaptor <GO> nAda, ssBVHNode <GO> curNode, GO newOb) { var left = curNode.Left; var right = curNode.Right; // merge and pushdown left and right as a new node.. var mergedSubnode = new ssBVHNode <GO>(nAda.BVH) { Left = left, Right = right, Parent = curNode, ContainedObjects = null }; // we need to be an interior node... so null out our object list.. left.Parent = mergedSubnode; right.Parent = mergedSubnode; mergedSubnode.ChildRefit(nAda, false); // make new subnode for obj var newSubnode = new ssBVHNode <GO>(nAda.BVH); newSubnode.Parent = curNode; newSubnode.ContainedObjects = new List <GO> { newOb }; nAda.MapObjectToBvhLeaf(newOb, newSubnode); newSubnode.ComputeVolume(nAda); // make assignments.. curNode.Left = mergedSubnode; curNode.Right = newSubnode; curNode.SetDepth(nAda, curNode.Depth); // propagate new depths to our children. curNode.ChildRefit(nAda); }
private void RemoveLeaf(SSBVHNodeAdaptor <GO> nAda, ssBVHNode <GO> removeLeaf) { if (Left == null || Right == null) { throw new Exception("bad intermediate node"); } ssBVHNode <GO> keepLeaf; if (removeLeaf == Left) { keepLeaf = Right; } else if (removeLeaf == Right) { keepLeaf = Left; } else { throw new Exception("removeLeaf doesn't match any leaf!"); } // "become" the leaf we are keeping. Bounds = keepLeaf.Bounds; Left = keepLeaf.Left; Right = keepLeaf.Right; ContainedObjects = keepLeaf.ContainedObjects; // clear the leaf.. // keepLeaf.left = null; keepLeaf.right = null; keepLeaf.gobjects = null; keepLeaf.parent = null; if (ContainedObjects == null) { Left.Parent = this; Right.Parent = this; // reassign child parents.. SetDepth(nAda, Depth); // this reassigns depth for our children } else { // map the objects we adopted to us... ContainedObjects.ForEach( o => { nAda.MapObjectToBvhLeaf(o, this); }); } // propagate our new volume.. if (Parent != null) { Parent.ChildRefit(nAda); } }
private static void AddObject(SSBVHNodeAdaptor <GO> nAda, ssBVHNode <GO> curNode, GO newOb, ref Bounds_d newObBox, double newObSAH) { // 1. first we traverse the node looking for the best leaf while (curNode.ContainedObjects == null) { // 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) var left = curNode.Left; var right = curNode.Right; double leftSAH = SA(left); double rightSAH = SA(right); double sendLeftSAH = rightSAH + SA(left.Bounds.ExpandedToFit(newObBox)); // (L+N,R) double sendRightSAH = leftSAH + SA(right.Bounds.ExpandedToFit(newObBox)); // (L,R+N) double mergedLeftAndRightSAH = SA(BoundsOfPair(left, right)) + newObSAH; // (L+R,N) // Doing a merge-and-pushdown can be expensive, so we only do it if it's notably better const double MERGE_DISCOUNT = 0.3f; if (mergedLeftAndRightSAH < (Math.Min(sendLeftSAH, sendRightSAH)) * MERGE_DISCOUNT) { addObject_Pushdown(nAda, curNode, newOb); return; } if (sendLeftSAH < sendRightSAH) { curNode = left; } else { curNode = right; } } // 2. then we add the object and map it to our leaf curNode.ContainedObjects.Add(newOb); nAda.MapObjectToBvhLeaf(newOb, curNode); curNode.RefitVolume(nAda); // split if necessary... curNode.SplitIfNecessary(nAda); }
private ssBVHNode(ssBVH <GO> bvh, ssBVHNode <GO> lparent, List <GO> gobjectlist, int curdepth) { SSBVHNodeAdaptor <GO> nAda = bvh.nAda; Parent = lparent; // save off the parent BVHGObj Node Depth = curdepth; if (bvh.MaxDepth < curdepth) { bvh.MaxDepth = curdepth; } // Early out check due to bad data // If the list is empty then we have no BVHGObj, or invalid parameters are passed in if (gobjectlist == null || gobjectlist.Count < 1) { throw new Exception("ssBVHNode constructed with invalid paramaters"); } // Check if we’re at our LEAF node, and if so, save the objects and stop recursing. Also store the min/max for the leaf node and update the parent appropriately if (gobjectlist.Count <= bvh.LEAF_OBJ_MAX) { // once we reach the leaf node, we must set prev/next to null to signify the end Left = null; Right = null; // at the leaf node we store the remaining objects, so initialize a list ContainedObjects = gobjectlist; ContainedObjects.ForEach(o => nAda.MapObjectToBvhLeaf(o, this)); ComputeVolume(nAda); SplitIfNecessary(nAda); } else { // -------------------------------------------------------------------------------------------- // if we have more than (bvh.LEAF_OBJECT_COUNT) objects, then compute the volume and split ContainedObjects = gobjectlist; ComputeVolume(nAda); SplitNode(nAda); ChildRefit(nAda, false); } }