ソースを参照

cull to geoms; fix box culling

David Rose 18 年 前
コミット
fe951a35fd

+ 14 - 9
panda/src/mathutil/boundingHexahedron.cxx

@@ -351,27 +351,32 @@ contains_box(const BoundingBox *box) const {
     float dist = p.dist_to_plane(center);
     float dist2 = dist * dist;
 
-    if (dist >= 0.0f && dist2 > radius2) {
-      // The sphere is completely in front of this plane; it's thus
-      // completely outside of the hexahedron.
-      return IF_no_intersection;
-
-    } else if (dist < 0.0f && dist2 < radius2) {
+    if (dist2 <= radius2) {
       // The sphere is not completely behind this plane, but some of
       // it is.
-
+      
       // Look a little closer.
       bool all_in = true;
-      for (int i = 0; i < 8 && all_in; ++i) {
+      bool all_out = true;
+      for (int i = 0; i < 8 && (all_in || all_out) ; ++i) {
         if (p.dist_to_plane(box->get_point(i)) < 0.0f) {
+          // This point is inside the plane.
+          all_out = false;
+        } else {
           // This point is outside the plane.
           all_in = false;
         }
       }
 
-      if (!all_in) {
+      if (all_out) {
+        return IF_no_intersection;
+      } else if (!all_in) {
         result &= ~IF_all;
       }
+
+    } else if (dist >= 0.0f) {
+      // The sphere is completely in front of this plane.
+      return IF_no_intersection;
     }
   }
 

+ 13 - 8
panda/src/mathutil/boundingPlane.cxx

@@ -173,27 +173,32 @@ contains_box(const BoundingBox *box) const {
   float dist = _plane.dist_to_plane(center);
   float dist2 = dist * dist;
 
-  if (dist >= 0.0f && dist2 > radius2) {
-    // The sphere is completely in front of this plane; it's thus
-    // completely outside of the hexahedron.
-    return IF_no_intersection;
-    
-  } else if (dist < 0.0f && dist2 < radius2) {
+  if (dist2 <= radius2) {
     // The sphere is not completely behind this plane, but some of
     // it is.
     
     // Look a little closer.
     bool all_in = true;
-    for (int i = 0; i < 8 && all_in; ++i) {
+    bool all_out = true;
+    for (int i = 0; i < 8 && (all_in || all_out) ; ++i) {
       if (_plane.dist_to_plane(box->get_point(i)) < 0.0f) {
+        // This point is inside the plane.
+        all_out = false;
+      } else {
         // This point is outside the plane.
         all_in = false;
       }
     }
     
-    if (!all_in) {
+    if (all_out) {
+      return IF_no_intersection;
+    } else if (!all_in) {
       result &= ~IF_all;
     }
+    
+  } else if (dist >= 0.0f) {
+    // The sphere is completely in front of this plane.
+    return IF_no_intersection;
   }
 
   return result;

+ 155 - 26
panda/src/pgraph/cullTraverser.cxx

@@ -260,14 +260,55 @@ traverse_below(CullTraverserData &data) {
       GeomNode::Geoms geoms = geom_node->get_geoms(_current_thread);
       int num_geoms = geoms.get_num_geoms();
       _geoms_pcollector.add_level(num_geoms);
+      CPT(TransformState) net_transform = data.get_net_transform(this);
+      CPT(TransformState) modelview_transform = data.get_modelview_transform(this);
+      CPT(TransformState) internal_transform = get_gsg()->get_cs_transform()->compose(modelview_transform);
+
       for (int i = 0; i < num_geoms; i++) {
-        CullableObject *object = new CullableObject(this, data, geoms, i);
-        if (object->_state->has_cull_callback() &&
-            !object->_state->cull_callback(this, data)) {
-          delete object;
-        } else {
-          _cull_handler->record_object(object, this);
+        const Geom *geom = geoms.get_geom(i);
+
+        CPT(RenderState) state = data._state->compose(geoms.get_geom_state(i));
+        if (state->has_cull_callback() && !state->cull_callback(this, data)) {
+          // Cull.
+          continue;
+        }
+
+        // Cull the Geom bounding volume against the view frustum
+        // and/or the cull planes.  Don't bother unless we've got more
+        // than one Geom, since otherwise the bounding volume of the
+        // GeomNode is (probably) the same as that of the one Geom,
+        // and we've already culled against that.
+        if (num_geoms > 1) {
+          if (data._view_frustum != (GeometricBoundingVolume *)NULL) {
+            // Cull the individual Geom against the view frustum.
+            CPT(BoundingVolume) geom_volume = geom->get_bounds();
+            const GeometricBoundingVolume *geom_gbv =
+              DCAST(GeometricBoundingVolume, geom_volume);
+
+            int result = data._view_frustum->contains(geom_gbv);
+            if (result == BoundingVolume::IF_no_intersection) {
+              // Cull this Geom.
+              continue;
+            }
+          }
+          if (!data._cull_planes->is_empty()) {
+            // Also cull the Geom against the cull planes.
+            CPT(BoundingVolume) geom_volume = geom->get_bounds();
+            const GeometricBoundingVolume *geom_gbv =
+              DCAST(GeometricBoundingVolume, geom_volume);
+            int result;
+            data._cull_planes->do_cull(result, state, geom_gbv);
+            if (result == BoundingVolume::IF_no_intersection) {
+              // Cull.
+              continue;
+            }
+          }
         }
+
+        CullableObject *object = 
+          new CullableObject(geom, state, net_transform, 
+                             modelview_transform, internal_transform);
+        _cull_handler->record_object(object, this);
       }
     }
 
@@ -365,6 +406,8 @@ is_in_view(CullTraverserData &data) {
 void CullTraverser::
 show_bounds(CullTraverserData &data, bool tight) {
   PandaNode *node = data.node();
+  CPT(TransformState) net_transform = data.get_net_transform(this);
+  CPT(TransformState) modelview_transform = data.get_modelview_transform(this);
 
   if (tight) {
     PT(Geom) bounds_viz = make_tight_bounds_viz(node);
@@ -373,16 +416,24 @@ show_bounds(CullTraverserData &data, bool tight) {
       _geoms_pcollector.add_level(1);
       CullableObject *outer_viz = 
         new CullableObject(bounds_viz, get_bounds_outer_viz_state(), 
-                           data.get_net_transform(this),
-                           data.get_modelview_transform(this),
+                           net_transform, modelview_transform,
                            get_gsg());
       _cull_handler->record_object(outer_viz, this);
     }
     
   } else {
     draw_bounding_volume(node->get_bounds(),
-                         data.get_net_transform(this),
-                         data.get_modelview_transform(this));
+                         net_transform, modelview_transform);
+
+    if (node->is_geom_node()) {
+      // Also show the bounding volumes of included Geoms.
+      GeomNode *gnode = DCAST(GeomNode, node);
+      int num_geoms = gnode->get_num_geoms();
+      for (int i = 0; i < num_geoms; ++i) {
+        draw_bounding_volume(gnode->get_geom(i)->get_bounds(), 
+                             net_transform, modelview_transform);
+      }
+    }
   }
 }
 
@@ -673,16 +724,55 @@ start_decal(const CullTraverserData &data) {
   GeomNode::Geoms geoms = geom_node->get_geoms();
   int num_geoms = geoms.get_num_geoms();
   _geoms_pcollector.add_level(num_geoms);
+  CPT(TransformState) net_transform = data.get_net_transform(this);
+  CPT(TransformState) modelview_transform = data.get_modelview_transform(this);
+  CPT(TransformState) internal_transform = get_gsg()->get_cs_transform()->compose(modelview_transform);
+  
   for (int i = num_geoms - 1; i >= 0; i--) {
-    CullableObject *next_object = 
-      new CullableObject(this, data, geoms, i, object);
-    if (next_object->_state->has_cull_callback() &&
-        !next_object->_state->cull_callback(this, data)) {
-      next_object->_next = NULL;
-      delete next_object;
-    } else {
-      object = next_object;
+    const Geom *geom = geoms.get_geom(i);
+
+    CPT(RenderState) state = data._state->compose(geoms.get_geom_state(i));
+    if (state->has_cull_callback() && !state->cull_callback(this, data)) {
+      // Cull.
+      continue;
     }
+    
+    // Cull the Geom bounding volume against the view frustum
+    // and/or the cull planes.  Don't bother unless we've got more
+    // than one Geom, since otherwise the bounding volume of the
+    // GeomNode is (probably) the same as that of the one Geom,
+    // and we've already culled against that.
+    if (num_geoms > 1) {
+      if (data._view_frustum != (GeometricBoundingVolume *)NULL) {
+        // Cull the individual Geom against the view frustum.
+        CPT(BoundingVolume) geom_volume = geom->get_bounds();
+        const GeometricBoundingVolume *geom_gbv =
+          DCAST(GeometricBoundingVolume, geom_volume);
+        
+        int result = data._view_frustum->contains(geom_gbv);
+        if (result == BoundingVolume::IF_no_intersection) {
+          // Cull this Geom.
+          continue;
+        }
+      }
+      if (!data._cull_planes->is_empty()) {
+        // Also cull the Geom against the cull planes.
+        CPT(BoundingVolume) geom_volume = geom->get_bounds();
+        const GeometricBoundingVolume *geom_gbv =
+          DCAST(GeometricBoundingVolume, geom_volume);
+        int result;
+        data._cull_planes->do_cull(result, state, geom_gbv);
+        if (result == BoundingVolume::IF_no_intersection) {
+          // Cull.
+          continue;
+        }
+      }
+    }
+    
+    object =
+      new CullableObject(geom, state, net_transform, 
+                         modelview_transform, internal_transform,
+                         object);
   }
 
   if (object != separator) {
@@ -743,16 +833,55 @@ r_get_decals(CullTraverserData &data, CullableObject *decals) {
       GeomNode::Geoms geoms = geom_node->get_geoms();
       int num_geoms = geoms.get_num_geoms();
       _geoms_pcollector.add_level(num_geoms);
+      CPT(TransformState) net_transform = data.get_net_transform(this);
+      CPT(TransformState) modelview_transform = data.get_modelview_transform(this);
+      CPT(TransformState) internal_transform = get_gsg()->get_cs_transform()->compose(modelview_transform);
+
       for (int i = num_geoms - 1; i >= 0; i--) {
-        CullableObject *next_decals = 
-          new CullableObject(this, data, geoms, i, decals);
-        if (next_decals->_state->has_cull_callback() &&
-            !next_decals->_state->cull_callback(this, data)) {
-          next_decals->_next = NULL;
-          delete next_decals;
-        } else {
-          decals = next_decals;
+        const Geom *geom = geoms.get_geom(i);
+
+        CPT(RenderState) state = data._state->compose(geoms.get_geom_state(i));
+        if (state->has_cull_callback() && !state->cull_callback(this, data)) {
+          // Cull.
+          continue;
         }
+
+        // Cull the Geom bounding volume against the view frustum
+        // and/or the cull planes.  Don't bother unless we've got more
+        // than one Geom, since otherwise the bounding volume of the
+        // GeomNode is (probably) the same as that of the one Geom,
+        // and we've already culled against that.
+        if (num_geoms > 1) {
+          if (data._view_frustum != (GeometricBoundingVolume *)NULL) {
+            // Cull the individual Geom against the view frustum.
+            CPT(BoundingVolume) geom_volume = geom->get_bounds();
+            const GeometricBoundingVolume *geom_gbv =
+              DCAST(GeometricBoundingVolume, geom_volume);
+
+            int result = data._view_frustum->contains(geom_gbv);
+            if (result == BoundingVolume::IF_no_intersection) {
+              // Cull this Geom.
+              continue;
+            }
+          }
+          if (!data._cull_planes->is_empty()) {
+            // Also cull the Geom against the cull planes.
+            CPT(BoundingVolume) geom_volume = geom->get_bounds();
+            const GeometricBoundingVolume *geom_gbv =
+              DCAST(GeometricBoundingVolume, geom_volume);
+            int result;
+            data._cull_planes->do_cull(result, state, geom_gbv);
+            if (result == BoundingVolume::IF_no_intersection) {
+              // Cull.
+              continue;
+            }
+          }
+        }
+
+        decals =
+          new CullableObject(geom, state, net_transform, 
+                             modelview_transform, internal_transform,
+                             decals);
       }
     }
   }

+ 13 - 12
panda/src/pgraph/cullableObject.I

@@ -31,19 +31,20 @@ CullableObject(CullableObject *next) :
 ////////////////////////////////////////////////////////////////////
 //     Function: CullableObject::Constructor
 //       Access: Public
-//  Description: Creates a CullableObject based on the ith Geom from
-//               the indicated GeomNode, with the render state from
-//               the indicated CullTraverserData.
+//  Description: Creates a CullableObject based the indicated geom,
+//               with the indicated render state and transform.
 ////////////////////////////////////////////////////////////////////
 INLINE CullableObject::
-CullableObject(const CullTraverser *trav, const CullTraverserData &data,
-               const GeomNode::Geoms &geoms, int i,
+CullableObject(const Geom *geom, const RenderState *state,
+               const TransformState *net_transform,
+               const TransformState *modelview_transform,
+               const GraphicsStateGuardianBase *gsg,
                CullableObject *next) :
-  _geom(geoms.get_geom(i)),
-  _state(data._state->compose(geoms.get_geom_state(i))),
-  _net_transform(data.get_net_transform(trav)),
-  _modelview_transform(data.get_modelview_transform(trav)),
-  _internal_transform(trav->get_gsg()->get_cs_transform()->compose(_modelview_transform)),
+  _geom(geom),
+  _state(state),
+  _net_transform(net_transform),
+  _modelview_transform(modelview_transform),
+  _internal_transform(gsg->get_cs_transform()->compose(modelview_transform)),
   _next(next)
 {
 }
@@ -58,13 +59,13 @@ INLINE CullableObject::
 CullableObject(const Geom *geom, const RenderState *state,
                const TransformState *net_transform,
                const TransformState *modelview_transform,
-               const GraphicsStateGuardianBase *gsg,
+               const TransformState *internal_transform,
                CullableObject *next) :
   _geom(geom),
   _state(state),
   _net_transform(net_transform),
   _modelview_transform(modelview_transform),
-  _internal_transform(gsg->get_cs_transform()->compose(modelview_transform)),
+  _internal_transform(internal_transform),
   _next(next)
 {
 }

+ 5 - 4
panda/src/pgraph/cullableObject.h

@@ -45,15 +45,16 @@ class CullTraverser;
 class EXPCL_PANDA CullableObject {
 public:
   INLINE CullableObject(CullableObject *next = NULL);
-  INLINE CullableObject(const CullTraverser *trav,
-                        const CullTraverserData &data,
-                        const GeomNode::Geoms &geoms, int i,
-                        CullableObject *next = NULL);
   INLINE CullableObject(const Geom *geom, const RenderState *state,
                         const TransformState *net_transform,
                         const TransformState *modelview_transform,
                         const GraphicsStateGuardianBase *gsg,
                         CullableObject *next = NULL);
+  INLINE CullableObject(const Geom *geom, const RenderState *state,
+                        const TransformState *net_transform,
+                        const TransformState *modelview_transform,
+                        const TransformState *internal_transform,
+                        CullableObject *next = NULL);
     
   INLINE CullableObject(const CullableObject &copy);
   INLINE void operator = (const CullableObject &copy);