Browse Source

working on culling node and bounding boxes

Ronen 8 years ago
parent
commit
84e90c8cbb

+ 0 - 3
MonoGameSceneGraph/Source/Entities/ModelEntity.cs

@@ -120,9 +120,6 @@ namespace MonoGameSceneGraph
         /// <returns>Bounding box of the entity.</returns>
         public BoundingBox GetBoundingBox(Node parent, Matrix localTransformations, Matrix worldTransformations)
         {
-            // apply model transformations on world transform (note: don't support animations)
-            worldTransformations = worldTransformations * Model.Bones[0].Transform;
-
             // initialize minimum and maximum corners of the bounding box to max and min values
             Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
             Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue);

+ 67 - 20
MonoGameSceneGraph/Source/Nodes/CullingNode.cs

@@ -29,8 +29,8 @@ namespace MonoGameSceneGraph
     /// For example, break the parent node into 4 nodes with 50x50 tiles each, and then break those nodes into 5x5 nodes with 10 tiles each. This way, the Culling Node will first test 4 large bounding box,
     /// with an actual chance of culling some of them. Then we'll have 25 bounding boxes to check per chunk, and some of them will cull out as well. For larger maps, just break into more chunks.
     /// 
-    /// Another thing you need to remember is that you can combine Culling Nodes with regular nodes. For example if you implemet particles or doodads (like grass) with lots of small nodes, sometimes its
-    /// enough to just test their parent node.
+    /// Another thing you need to remember is that you can combine Culling Nodes with regular nodes, but the regular nodes must be the edges (eg [culling_node] -> [plain_node] -> [culling_node] will not work properly). 
+    /// For example if you implemet particles or doodads (like grass) with lots of small nodes, sometimes its enough to just test their parent node.
     /// </remarks>
     public class CullingNode : Node
     {
@@ -43,22 +43,13 @@ namespace MonoGameSceneGraph
         /// <summary>
         /// Last calculated bounding box for this node.
         /// </summary>
-        protected BoundingBox _currBoundingBox;
+        protected BoundingBox _boundingBox;
 
         /// <summary>
-        /// Do we need to recalculate the bounding box of this node?
+        /// Do we need to update the bounding box?
         /// </summary>
         private bool _isBoundingBoxDirty = true;
 
-        /// <summary>
-        /// Called when the world matrix of this node is actually recalculated (invoked after the calculation).
-        /// </summary>
-        protected override void OnWorldMatrixChange()
-        {
-            base.OnWorldMatrixChange();
-            _isBoundingBoxDirty = true;
-        }
-
         /// <summary>
         /// Draw the node and its children.
         /// </summary>
@@ -80,15 +71,11 @@ namespace MonoGameSceneGraph
             // update transformations (only if needed, testing logic is inside)
             UpdateTransformations();
 
-            // check if need to recalculate bounding box
-            if (_isBoundingBoxDirty)
-            {
-                _currBoundingBox = GetBoundingBox(true);
-                _isBoundingBoxDirty = false;
-            }
+            // update bounding box (only if needed, testing logic is inside)
+            UpdateBoundingBox();
 
             // if this node is out of screen, don't draw it
-            if (CameraFrustum.Contains(_currBoundingBox) == ContainmentType.Disjoint)
+            if (CameraFrustum.Contains(_boundingBox) == ContainmentType.Disjoint)
             {
                 return;
             }
@@ -107,5 +94,65 @@ namespace MonoGameSceneGraph
                 entity.Draw(this, _localTransform, _worldTransform);
             }
         }
+
+        /// <summary>
+        /// Called every time one of the child nodes recalculate world transformations.
+        /// </summary>
+        /// <param name="node">The child node that updated.</param>
+        public override void OnChildWorldMatrixChange(Node node)
+        {
+            // mark bounding box as needing update
+            _isBoundingBoxDirty = true;
+
+            // pass message to parent, because it needs to update bounding box as well
+            if (_parent != null)
+            {
+                _parent.OnChildWorldMatrixChange(node);
+            }
+        }
+
+        /// <summary>
+        /// Get bounding box of this node and all its child nodes.
+        /// </summary>
+        /// <param name="includeChildNodes">If true, will include bounding box of child nodes. If false, only of entities directly attached to this node.</param>
+        /// <returns>Bounding box of the node and its children.</returns>
+        public override BoundingBox GetBoundingBox(bool includeChildNodes = true)
+        {
+            // update bounding box (note: only if needed, tested inside)
+            UpdateBoundingBox();
+
+            // return bounding box
+            return _boundingBox;
+        }
+
+        /// <summary>
+        /// Called when the world matrix of this node is actually recalculated (invoked after the calculation).
+        /// </summary>
+        protected override void OnWorldMatrixChange()
+        {
+            // call base function
+            base.OnWorldMatrixChange();
+
+            // set bounding box to dirty
+            _isBoundingBoxDirty = true;
+        }
+
+        /// <summary>
+        /// Update the bounding box of this Culling Node.
+        /// </summary>
+        protected void UpdateBoundingBox()
+        {
+            // if bounding box is not dirty, skip
+            if (!_isBoundingBoxDirty)
+            {
+                return;
+            }
+
+            // update bounding box
+            _boundingBox = base.GetBoundingBox(true);
+
+            // bounding box no longer dirty
+            _isBoundingBoxDirty = false;
+        }
     }
 }

+ 23 - 0
MonoGameSceneGraph/Source/Nodes/Node.cs

@@ -237,7 +237,14 @@ namespace MonoGameSceneGraph
         /// </summary>
         protected virtual void OnWorldMatrixChange()
         {
+            // update transformations version
             _transformVersion++;
+            
+            // notify parent
+            if (_parent != null)
+            {
+                _parent.OnChildWorldMatrixChange(this);
+            }
         }
 
         /// <summary>
@@ -462,6 +469,14 @@ namespace MonoGameSceneGraph
             OnTransformationsSet();
         }
 
+        /// <summary>
+        /// Called every time one of the child nodes recalculate world transformations.
+        /// </summary>
+        /// <param name="node">The child node that updated.</param>
+        public virtual void OnChildWorldMatrixChange(Node node)
+        {
+        }
+
         /// <summary>
         /// Get bounding box of this node and all its child nodes.
         /// </summary>
@@ -469,6 +484,9 @@ namespace MonoGameSceneGraph
         /// <returns>Bounding box of the node and its children.</returns>
         public virtual BoundingBox GetBoundingBox(bool includeChildNodes = true)
         {
+            // make sure transformations are up-to-date
+            UpdateTransformations();
+
             // initialize minimum and maximum corners of the bounding box to max and min values
             Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
             Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue);
@@ -481,6 +499,8 @@ namespace MonoGameSceneGraph
                     BoundingBox curr = child.GetBoundingBox();
                     min = Vector3.Min(min, curr.Min);
                     max = Vector3.Max(max, curr.Max);
+                    min = Vector3.Min(min, curr.Max);
+                    max = Vector3.Max(max, curr.Min);
                 }
             }
 
@@ -490,6 +510,9 @@ namespace MonoGameSceneGraph
                 BoundingBox curr = entity.GetBoundingBox(this, _localTransform, _worldTransform);
                 min = Vector3.Min(min, curr.Min);
                 max = Vector3.Max(max, curr.Max);
+                min = Vector3.Min(min, curr.Max);
+                max = Vector3.Max(max, curr.Min);
+
             }
 
             // return final bounding box

+ 1 - 1
README.md

@@ -190,7 +190,7 @@ But in addition to creating and drawing them, you also need to set the camera bo
 MonoGameSceneGraph.CullingNode.CameraFrustum = cameraFrustum;
 ```
 
-Note that you can mix CullingNodes with regular Nodes without any problems. If you have internal parts that you don't want to check culling for, just make them plain Nodes. However, if you put them under a CullingNode and its culled out, they won't be rendered.
+Note that you can mix CullingNodes with regular Nodes, but make sure the plain nodes are only in edges and not between CullingNodes.
 
 #### Using CullingNodes Properly
 As mentioned above, a CullingNode bounding box is the combination of its own bounding box + all its children nodes and entities.