/// /// A simple node in an Octree. /// public class OctreeNode : Node { /* * CONSTANTS */ /// /// the number of children in an octree is 8. /// I made this a constant in case the fundemental nature /// of three dimensional space changes one day and I needed /// to change it. /// public const int NUM_TREE_CHILDREN = 8; /* * CLASS PROPERTIES */ /// /// the parent of this tree node /// protected OctreeNode curParent; /// /// the root of this tree node /// protected Octree curTree; /// /// the box defining this tree node /// protected Bounds box; /// /// the node children (if null node is a leaf) /// protected OctreeNode[] children; /// /// depth in the tree that this node defines /// protected uint treeLevel; /* * CONSTRUCTOR */ /// /// recursive constructor to create a new octree node and children /// /// an octree object that holds the root of the tree /// the tree node that is the parent to this one /// the TwelveCylinder game object /// the box that defines the new tree node /// the current depth in the tree of this node /// the maximum subdivision level of the tree node where 0 is the root node public OctreeNode(Octree newTree, OctreeNode newParent, TwelveCylinderGame newGame, Bounds newBox, uint depth, uint maxDivisions) : base(newGame, "octree node", NodeType.SceneItem) { if (newBox == null) throw new ArgumentNullException("Octree node requires non-null bounds."); curTree = newTree; //parent octree curParent = newParent; //parent tree node //tree node bounds box = newBox; treeLevel = depth; // if subdivision still needed if (depth < maxDivisions) subdivide(maxDivisions); else curTree.addLeafNode(this); } //additional constructors omitted /* * UNLOADING */ /// /// unloads this collision tree node and it's children /// /// public override void unload(bool disposeResources) { base.unload(disposeResources); curParent = null; curTree = null; box = null; if (children != null) { for (int i = 0; i < OctreeNode.NUM_TREE_CHILDREN; i++) children[i].unload(disposeResources); children = null; } } /* * METHODS */ /// /// recursive method to get the leaf nodes which intersect with the specified bound box /// /// a bounding box to test /// the output list of leaf nodes that intersect with the bounds public void GetIntersectedLeafNodes(Bounds b, ref List leafNodes) { if (!b.BoxOverlap(box)) return; //test box does not overlap with tree node's box if (children != null) { // if not a leaf node, recurse to all children foreach (OctreeNode child in children) child.GetIntersectedLeafNodes(b, ref leafNodes); } else leafNodes.Add(this); } /// /// recursive function to find the octree leaf node that contains /// the specified world position /// /// a world space coordinate /// the containing leaf node public virtual OctreeNode getContainingLeaf(Vector3 worldPos) { if (box.PointInside(worldPos)) { if (children == null) return this; OctreeNode curLeaf = null; foreach (OctreeNode node in children) { curLeaf = node.getContainingLeaf(worldPos); if (curLeaf != null) return curLeaf; } } return null; } /// /// recursively gets the maximum depth of this tree branch /// /// the maximum tree depth contained by this branch public virtual uint getMaximumDepth() { if (children == null) return treeLevel; else { uint maxDepth = 0; uint curDepth; for (int i = 0; i < NUM_TREE_CHILDREN; i++) { curDepth = children[i].getMaximumDepth(); if (curDepth > maxDepth) maxDepth = curDepth; } return maxDepth; } } /// /// Gets an array of child Bounds that subdivide /// this tree node into 8 equal parts. /// /// an array of 8 Bounds protected virtual Bounds[] getChildNodeBounds() { Vector3 center = box.Center; Bounds[] children = new Bounds[NUM_TREE_CHILDREN]; Vector3 min = box.Min; Vector3 max = box.Max; Vector3 center = box.Center; children[0] = new Bounds(curGame, min, center); children[1] = new Bounds(curGame, new Vector3(center.X, min.Y, min.Z), new Vector3(max.X, center.Y, center.Z)); children[2] = new Bounds(curGame, new Vector3(min.X, center.Y, min.Z), new Vector3(center.X, max.Y, center.Z)); children[3] = new Bounds(curGame, new Vector3(center.X, center.Y, min.Z), new Vector3(max.X, max.Y, center.Z)); children[4] = new Bounds(curGame, new Vector3(min.X, min.Y, center.Z), new Vector3(center.X, center.Y, max.Z)); children[5] = new Bounds(curGame, new Vector3(center.X, min.Y, center.Z), new Vector3(max.X, center.Y, max.Z)); children[6] = new Bounds(curGame, new Vector3(min.X, center.Y, center.Z), new Vector3(center.X, max.Y, max.Z)); children[7] = new Bounds(curGame, center, max); return children; } /// /// Subdivides this node in the octree into 8 children /// and recursively continues octree creation. /// protected virtual void subdivide(uint maxDivisions) { uint childDepth = treeLevel + 1; // create the 8 children children = new OctreeNode[NUM_TREE_CHILDREN]; Bounds[] childrenBox = getChildNodeBounds(); // increment subdivision level and create new tree nodes for (uint i = 0; i < NUM_TREE_CHILDREN; i++) children[i] = new OctreeNode(curTree, this, curGame, childrenBox[i], childDepth, maxDivisions); } //encapsulators omitted /* * UPDATE */ public override void update(GameTime gameTime, TwelveCylinder.GameCamera.Camera curCam, Matrix projMatrix, Matrix viewProjection) { base.update(gameTime, curCam, projMatrix, viewProjection); //update octree children nodes if (children != null) foreach (OctreeNode treeNode in children) treeNode.update(gameTime, curCam, projMatrix, viewProjection); } /* * RENDER */ /// /// recursively draws the boundaries of this tree node and its children to the specified depth /// /// the maximum depth to drill into this tree and draw bounds public virtual void DrawTreeBounds(uint depth) { box.Render(); if (children != null && depth > 0) { depth--; for (int i = 0; i < OctreeNode.NUM_TREE_CHILDREN; i++) children[i].DrawTreeBounds(depth); } } }