瀏覽代碼

further occluder enhancements from teedee

David Rose 14 年之前
父節點
當前提交
1b8d55ce34
共有 4 個文件被更改,包括 136 次插入84 次删除
  1. 109 83
      panda/src/pgraph/cullPlanes.cxx
  2. 21 0
      panda/src/pgraph/occluderNode.I
  3. 3 1
      panda/src/pgraph/occluderNode.cxx
  4. 3 0
      panda/src/pgraph/occluderNode.h

+ 109 - 83
panda/src/pgraph/cullPlanes.cxx

@@ -130,6 +130,10 @@ apply_state(const CullTraverser *trav, const CullTraverserData *data,
 
   if (node_effect != (OccluderEffect *)NULL) {
     CPT(TransformState) center_transform = NULL;
+    // We'll need to know the occluder's frustum in cull-center
+    // space.
+    SceneSetup *scene = trav->get_scene();
+    const Lens *lens = scene->get_lens();
 
     int num_on_occluders = node_effect->get_num_on_occluders();
     for (int i = 0; i < num_on_occluders; ++i) {
@@ -139,10 +143,6 @@ apply_state(const CullTraverser *trav, const CullTraverserData *data,
         // Here's a new occluder; consider adding it to the list.
         OccluderNode *occluder_node = DCAST(OccluderNode, occluder.node());
         nassertr(occluder_node->get_num_vertices() == 4, new_planes);
-        
-        // We'll need to know the occluder's frustum in cull-center
-        // space.
-        SceneSetup *scene = trav->get_scene();
 
         CPT(TransformState) occluder_transform = occluder.get_transform(scene->get_cull_center());
 
@@ -163,69 +163,44 @@ apply_state(const CullTraverser *trav, const CullTraverserData *data,
         // we might as well make a BoundingBox, which is as tight as
         // possible, and creating one isn't any less efficient than
         // transforming the existing bounding volume.
-	PT(BoundingBox) occluder_gbv;
-	{
-	  // Get a transform from the occluder directly to this node's
-	  // space for comparing with the current view frustum.
-	  CPT(TransformState) composed_transform = center_transform->compose(occluder_transform);
-	  const LMatrix4f &composed_mat = composed_transform->get_mat();
-	  LPoint3f ccp[4];
-	  ccp[0] = occluder_node->get_vertex(0) * composed_mat;
-	  ccp[1] = occluder_node->get_vertex(1) * composed_mat;
-	  ccp[2] = occluder_node->get_vertex(2) * composed_mat;
-	  ccp[3] = occluder_node->get_vertex(3) * composed_mat;
-
-	  LPoint3f ccp_min(min(min(ccp[0][0], ccp[1][0]), 
-			       min(ccp[2][0], ccp[3][0])),
-			   min(min(ccp[0][1], ccp[1][1]), 
-			       min(ccp[2][1], ccp[3][1])),
-			   min(min(ccp[0][2], ccp[1][2]), 
-			       min(ccp[2][2], ccp[3][2])));
-	  LPoint3f ccp_max(max(max(ccp[0][0], ccp[1][0]), 
-			       max(ccp[2][0], ccp[3][0])),
-			   max(max(ccp[0][1], ccp[1][1]), 
-			       max(ccp[2][1], ccp[3][1])),
-			   max(max(ccp[0][2], ccp[1][2]), 
-			       max(ccp[2][2], ccp[3][2])));
-			   			   
-	  occluder_gbv = new BoundingBox(ccp_min, ccp_max);
-        }
-
-	if (data->_view_frustum != (GeometricBoundingVolume *)NULL) {
-	  int occluder_result = data->_view_frustum->contains(occluder_gbv);
-	  if (occluder_result == BoundingVolume::IF_no_intersection) {
-	    // This occluder is outside the view frustum; ignore it.
-	    if (pgraph_cat.is_spam()) {
-	      pgraph_cat.spam()
-		<< "Ignoring occluder " << occluder << ": outside view frustum.\n";
-	    }
-	    continue;
-	  }
-	}
-
-        // Also check if the new occluder is completely within any of
-        // our existing occluder volumes.
-        bool is_enclosed = false;
-        Occluders::const_iterator oi;
-        for (oi = _occluders.begin(); oi != _occluders.end(); ++oi) {
-          int occluder_result = (*oi).second->contains(occluder_gbv);
-          if ((occluder_result & BoundingVolume::IF_all) != 0) {
-            is_enclosed = true;
-            break;
+        PT(BoundingBox) occluder_gbv;
+        // Get a transform from the occluder directly to this node's
+        // space for comparing with the current view frustum.
+        CPT(TransformState) composed_transform = center_transform->compose(occluder_transform);
+        const LMatrix4f &composed_mat = composed_transform->get_mat();
+        LPoint3f ccp[4];
+        ccp[0] = occluder_node->get_vertex(0) * composed_mat;
+        ccp[1] = occluder_node->get_vertex(1) * composed_mat;
+        ccp[2] = occluder_node->get_vertex(2) * composed_mat;
+        ccp[3] = occluder_node->get_vertex(3) * composed_mat;
+
+        LPoint3f ccp_min(min(min(ccp[0][0], ccp[1][0]), 
+                     min(ccp[2][0], ccp[3][0])),
+                 min(min(ccp[0][1], ccp[1][1]), 
+                     min(ccp[2][1], ccp[3][1])),
+                 min(min(ccp[0][2], ccp[1][2]), 
+                     min(ccp[2][2], ccp[3][2])));
+        LPoint3f ccp_max(max(max(ccp[0][0], ccp[1][0]), 
+                     max(ccp[2][0], ccp[3][0])),
+                 max(max(ccp[0][1], ccp[1][1]), 
+                     max(ccp[2][1], ccp[3][1])),
+                 max(max(ccp[0][2], ccp[1][2]), 
+                     max(ccp[2][2], ccp[3][2])));
+
+        occluder_gbv = new BoundingBox(ccp_min, ccp_max);
+
+        if (data->_view_frustum != (GeometricBoundingVolume *)NULL) {
+          int occluder_result = data->_view_frustum->contains(occluder_gbv);
+          if (occluder_result == BoundingVolume::IF_no_intersection) {
+            // This occluder is outside the view frustum; ignore it.
+            if (pgraph_cat.is_spam()) {
+              pgraph_cat.spam()
+            << "Ignoring occluder " << occluder << ": outside view frustum.\n";
+            }
+            continue;
           }
         }
-        if (is_enclosed) {
-          // No reason to add this occluder; it's behind an existing
-          // occluder.
-	  if (pgraph_cat.is_spam()) {
-	    pgraph_cat.spam()
-	      << "Ignoring occluder " << occluder << ": behind another.\n";
-	  }
-          continue;
-        }
-        // TODO: perhaps we should also check whether any existing
-        // occluders are fully contained within this new one.
-        
+
         // Get the occluder geometry in cull-center space.
         const LMatrix4f &occluder_mat = occluder_transform->get_mat();
         LPoint3f points_near[4];
@@ -233,8 +208,8 @@ apply_state(const CullTraverser *trav, const CullTraverserData *data,
         points_near[1] = occluder_node->get_vertex(1) * occluder_mat;
         points_near[2] = occluder_node->get_vertex(2) * occluder_mat;
         points_near[3] = occluder_node->get_vertex(3) * occluder_mat;
-        
         Planef plane(points_near[0], points_near[1], points_near[2]);
+        
         if (plane.get_normal().dot(LVector3f::forward()) >= 0.0) {
           if (occluder_node->is_double_sided()) {
             swap(points_near[0], points_near[3]);
@@ -242,21 +217,21 @@ apply_state(const CullTraverser *trav, const CullTraverserData *data,
             plane = Planef(points_near[0], points_near[1], points_near[2]);
           } else {
             // This occluder is facing the wrong direction.  Ignore it.
-	    if (pgraph_cat.is_spam()) {
-	      pgraph_cat.spam()
-		<< "Ignoring occluder " << occluder << ": wrong direction.\n";
-	    }
+            if (pgraph_cat.is_spam()) {
+              pgraph_cat.spam()
+                << "Ignoring occluder " << occluder << ": wrong direction.\n";
+            }
             continue;
           }
         }
 
-        float near_clip = scene->get_lens()->get_near();
+        float near_clip = lens->get_near();
         if (plane.dist_to_plane(LPoint3f::zero()) <= near_clip) {
           // This occluder is behind the camera's near plane.  Ignore it.
-	  if (pgraph_cat.is_spam()) {
-	    pgraph_cat.spam()
-	      << "Ignoring occluder " << occluder << ": behind near plane.\n";
-	  }
+          if (pgraph_cat.is_spam()) {
+            pgraph_cat.spam()
+              << "Ignoring occluder " << occluder << ": behind near plane.\n";
+          }
           continue;
         }
 
@@ -264,13 +239,14 @@ apply_state(const CullTraverser *trav, const CullTraverserData *data,
         float d1 = points_near[1].dot(LVector3f::forward());
         float d2 = points_near[2].dot(LVector3f::forward());
         float d3 = points_near[3].dot(LVector3f::forward());
+
         if (d0 <= near_clip && d1 <= near_clip && d2 <= near_clip && d3 <= near_clip) {
           // All four corners of the occluder are behind the camera's
           // near plane.  Ignore it.
-	  if (pgraph_cat.is_spam()) {
-	    pgraph_cat.spam()
-	      << "Ignoring occluder " << occluder << ": behind near plane (test 2).\n";
-	  }
+          if (pgraph_cat.is_spam()) {
+            pgraph_cat.spam()
+              << "Ignoring occluder " << occluder << ": behind near plane (test 2).\n";
+        }
           continue;
         }
 
@@ -285,12 +261,62 @@ apply_state(const CullTraverser *trav, const CullTraverserData *data,
         if (d0 <= 0.0 || d1 <= 0.0 || d2 <= 0.0 || d3 <= 0.0) {
           // One of the corners is behind the y = 0 plane.  We can't
           // handle this case.  Ignore it.
-	  if (pgraph_cat.is_spam()) {
-	    pgraph_cat.spam()
-	      << "Ignoring occluder " << occluder << ": partly behind zero plane.\n";
-	  }
+          if (pgraph_cat.is_spam()) {
+            pgraph_cat.spam()
+              << "Ignoring occluder " << occluder << ": partly behind zero plane.\n";
+          }
+          continue;
+        }
+
+        if (occluder_node->get_min_coverage()) {
+          LPoint3f coords[4];
+          lens->project(points_near[0], coords[0]);
+          lens->project(points_near[1], coords[1]);
+          lens->project(points_near[2], coords[2]);
+          lens->project(points_near[3], coords[3]);
+          coords[0][0] = max(-1, min(1, coords[0][0]));
+          coords[0][1] = max(-1, min(1, coords[0][1]));
+          coords[1][0] = max(-1, min(1, coords[1][0]));
+          coords[1][1] = max(-1, min(1, coords[1][1]));
+          coords[2][0] = max(-1, min(1, coords[2][0]));
+          coords[2][1] = max(-1, min(1, coords[2][1]));
+          coords[3][0] = max(-1, min(1, coords[3][0]));
+          coords[3][1] = max(-1, min(1, coords[3][1]));
+          float coverage = ((coords[0] - coords[1]).cross(coords[0] - coords[2]).length()
+                          + (coords[3] - coords[1]).cross(coords[3] - coords[2]).length())
+                          * 0.125;
+          if (coverage < occluder_node->get_min_coverage()) {
+            // The occluder does not cover enough screen space.  Ignore it.
+            if (pgraph_cat.is_spam()) {
+              pgraph_cat.spam()
+                << "Ignoring occluder " << occluder << ": coverage less than minimum.\n";
+            }
+            continue;
+          }
+        }
+
+        // Also check if the new occluder is completely within any of
+        // our existing occluder volumes.
+        bool is_enclosed = false;
+        Occluders::const_iterator oi;
+        for (oi = _occluders.begin(); oi != _occluders.end(); ++oi) {
+          int occluder_result = (*oi).second->contains(occluder_gbv);
+          if ((occluder_result & BoundingVolume::IF_all) != 0) {
+            is_enclosed = true;
+            break;
+          }
+        }
+        if (is_enclosed) {
+          // No reason to add this occluder; it's behind an existing
+          // occluder.
+          if (pgraph_cat.is_spam()) {
+            pgraph_cat.spam()
+              << "Ignoring occluder " << occluder << ": behind another.\n";
+          }
           continue;
         }
+        // TODO: perhaps we should also check whether any existing
+        // occluders are fully contained within this new one.
 
         // Project those four lines to the camera's far plane.
         float far_clip = scene->get_lens()->get_far();

+ 21 - 0
panda/src/pgraph/occluderNode.I

@@ -70,3 +70,24 @@ INLINE void OccluderNode::set_double_sided(bool value) {
 INLINE bool OccluderNode::is_double_sided() {
   return _double_sided;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: OccluderNode::set_min_coverage
+//       Access: Published
+//  Description: Minimum screen coverage needed before occluder used.
+//               Range should be 0 to 1. For example, setting to 0.2
+//               would mean that the occluder needs to cover 20% of
+//               the screen to be considered.
+////////////////////////////////////////////////////////////////////
+INLINE void OccluderNode::set_min_coverage(float value) {
+  _min_coverage = value;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OccluderNode::get_min_coverage
+//       Access: Published
+//  Description: Returns the minimum screen coverage.
+////////////////////////////////////////////////////////////////////
+INLINE float OccluderNode::get_min_coverage() {
+  return _min_coverage;
+}

+ 3 - 1
panda/src/pgraph/occluderNode.cxx

@@ -62,6 +62,7 @@ OccluderNode(const string &name) :
   // OccluderNodes are hidden by default.
   set_overall_hidden(true);
   set_double_sided(false);
+  set_min_coverage(0.0);
   set_vertices(LPoint3f::rfu(-1.0, 0.0, -1.0),
                LPoint3f::rfu(1.0, 0.0, -1.0),
                LPoint3f::rfu(1.0, 0.0, 1.0),
@@ -77,7 +78,8 @@ OccluderNode::
 OccluderNode(const OccluderNode &copy) :
   PandaNode(copy),
   _vertices(copy._vertices),
-  _double_sided(copy._double_sided)
+  _double_sided(copy._double_sided),
+  _min_coverage(copy._min_coverage)
 {
 }
 

+ 3 - 0
panda/src/pgraph/occluderNode.h

@@ -53,6 +53,8 @@ public:
 PUBLISHED:
   INLINE void set_double_sided(bool value);
   INLINE bool is_double_sided();
+  INLINE void set_min_coverage(float value);
+  INLINE float get_min_coverage();
   INLINE void set_vertices(const LPoint3f &v0, const LPoint3f &v1,
                            const LPoint3f &v2, const LPoint3f &v3);
   INLINE int get_num_vertices() const;
@@ -70,6 +72,7 @@ protected:
 
 private:
   bool _double_sided;
+  float _min_coverage;
   typedef pvector<LPoint3f> Vertices;
   Vertices _vertices;