Browse Source

pgraph: Optimization for GeomNode::add_for_draw()

rdb 5 years ago
parent
commit
2b29c757d9
3 changed files with 69 additions and 38 deletions
  1. 23 0
      panda/src/gobj/geom.cxx
  2. 2 0
      panda/src/gobj/geom.h
  3. 44 38
      panda/src/pgraph/geomNode.cxx

+ 23 - 0
panda/src/gobj/geom.cxx

@@ -1294,6 +1294,29 @@ prepare_now(PreparedGraphicsObjects *prepared_objects,
   return gc;
 }
 
+/**
+ * Returns true if the Geom is within the given view frustum.
+ */
+bool Geom::
+is_in_view(const BoundingVolume *view_frustum, Thread *current_thread) const {
+  CDLockedReader cdata(_cycler, current_thread);
+
+  if (cdata->_user_bounds != nullptr) {
+    const GeometricBoundingVolume *gbv = cdata->_user_bounds->as_geometric_bounding_volume();
+    return view_frustum->contains(gbv) != BoundingVolume::IF_no_intersection;
+  }
+  else if (!cdata->_internal_bounds_stale) {
+    const GeometricBoundingVolume *gbv = cdata->_internal_bounds->as_geometric_bounding_volume();
+    return view_frustum->contains(gbv) != BoundingVolume::IF_no_intersection;
+  }
+  else {
+    CDWriter cdataw(((Geom *)this)->_cycler, cdata, false);
+    compute_internal_bounds(cdataw, current_thread);
+    const GeometricBoundingVolume *gbv = cdataw->_internal_bounds->as_geometric_bounding_volume();
+    return view_frustum->contains(gbv) != BoundingVolume::IF_no_intersection;
+  }
+}
+
 /**
  * Actually draws the Geom with the indicated GSG, using the indicated vertex
  * data (which might have been pre-munged to support the GSG's needs).

+ 2 - 0
panda/src/gobj/geom.h

@@ -157,6 +157,8 @@ PUBLISHED:
                            GraphicsStateGuardianBase *gsg);
 
 public:
+  bool is_in_view(const BoundingVolume *view_frustum, Thread *current_thread) const;
+
   bool draw(GraphicsStateGuardianBase *gsg,
             const GeomVertexData *vertex_data, size_t num_instances,
             bool force, Thread *current_thread) const;

+ 44 - 38
panda/src/pgraph/geomNode.cxx

@@ -516,44 +516,50 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) {
   trav->_geoms_pcollector.add_level(num_geoms);
   CPT(TransformState) internal_transform = data.get_internal_transform(trav);
 
-  for (int i = 0; i < num_geoms; i++) {
-    CPT(Geom) geom = geoms.get_geom(i);
-    if (geom->is_empty()) {
-      continue;
-    }
-
-    CPT(RenderState) state = data._state->compose(geoms.get_geom_state(i));
-    if (state->has_cull_callback() && !state->cull_callback(trav, data)) {
-      // Cull.
-      continue;
+  if (num_geoms == 1) {
+    // If there's only one Geom, we don't need to bother culling each individual
+    // Geom bounding volume against the view frustum, since we've already
+    // checked the one on the GeomNode itself.
+    CPT(Geom) geom = geoms.get_geom(0);
+    if (!geom->is_empty()) {
+      CPT(RenderState) state = data._state->compose(geoms.get_geom_state(0));
+      if (!state->has_cull_callback() || state->cull_callback(trav, data)) {
+        CullableObject *object =
+          new CullableObject(std::move(geom), std::move(state), std::move(internal_transform));
+        object->_instances = data._instances;
+        trav->get_cull_handler()->record_object(object, trav);
+      }
     }
+  }
+  else {
+    // More than one Geom.
+    for (int i = 0; i < num_geoms; i++) {
+      CPT(Geom) geom = geoms.get_geom(i);
+      if (geom->is_empty()) {
+        continue;
+      }
 
-    if (data._instances != nullptr) {
-      // Draw each individual instance.  We don't bother culling each
-      // individual Geom for each instance; that is probably way too slow.
-      CullableObject *object =
-        new CullableObject(std::move(geom), std::move(state), internal_transform);
-      object->_instances = data._instances;
-      trav->get_cull_handler()->record_object(object, trav);
-      continue;
-    }
+      CPT(RenderState) state = data._state->compose(geoms.get_geom_state(i));
+      if (state->has_cull_callback() && !state->cull_callback(trav, data)) {
+        // Cull.
+        continue;
+      }
 
-    // Cull the Geom bounding volume against the view frustum andor 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 != nullptr) {
-        // Cull the individual Geom against the view frustum.
-        CPT(BoundingVolume) geom_volume = geom->get_bounds(current_thread);
-        const GeometricBoundingVolume *geom_gbv =
-          geom_volume->as_geometric_bounding_volume();
+      if (data._instances != nullptr) {
+        // Draw each individual instance.  We don't bother culling each
+        // individual Geom for each instance; that is probably way too slow.
+        CullableObject *object =
+          new CullableObject(std::move(geom), std::move(state), internal_transform);
+        object->_instances = data._instances;
+        trav->get_cull_handler()->record_object(object, trav);
+        continue;
+      }
 
-        int result = data._view_frustum->contains(geom_gbv);
-        if (result == BoundingVolume::IF_no_intersection) {
-          // Cull this Geom.
-          continue;
-        }
+      // Cull the individual Geom against the view frustum.
+      if (data._view_frustum != nullptr &&
+          !geom->is_in_view(data._view_frustum, current_thread)) {
+        // Cull this Geom.
+        continue;
       }
       if (!data._cull_planes->is_empty()) {
         // Also cull the Geom against the cull planes.
@@ -567,11 +573,11 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) {
           continue;
         }
       }
-    }
 
-    CullableObject *object =
-      new CullableObject(std::move(geom), std::move(state), internal_transform);
-    trav->get_cull_handler()->record_object(object, trav);
+      CullableObject *object =
+        new CullableObject(std::move(geom), std::move(state), internal_transform);
+      trav->get_cull_handler()->record_object(object, trav);
+    }
   }
 }