Browse Source

fix problem with local transform on occluder; add egg bface support for occluders

David Rose 14 years ago
parent
commit
19d52c3221

+ 9 - 0
panda/src/doc/eggSyntax.txt

@@ -1320,6 +1320,15 @@ GROUPING ENTRIES
     is constant-color or a related option, this defines the constant
     color that will be used.
 
+  <Scalar> occluder { boolean-value }
+
+    This makes the first (or only) polygon within this group node into
+    an occluder.  The polygon must have exactly four vertices.  An
+    occluder polygon is invisible.  When the occluder is activated
+    with model.set_occluder(occluder), objects that are behind the
+    occluder will not be drawn.  This can be a useful rendering
+    optimization for complex scenes, but should not be overused or
+    performance can suffer.
 
   OTHER GROUP ATTRIBUTES
 

+ 14 - 14
panda/src/egg/eggGroup.cxx

@@ -233,19 +233,19 @@ write(ostream &out, int indent_level) const {
   }
 
   if(get_scroll_u() != 0) {
-    indent(out, indent_level) 
+    indent(out, indent_level + 2) 
       << "<Scalar> scroll_u { " << get_scroll_u() << " }\n";
 
   }
 
   if(get_scroll_v() != 0) {
-    indent(out, indent_level) 
+    indent(out, indent_level + 2) 
       << "<Scalar> scroll_v { " << get_scroll_v() << " }\n";
 
   }
 
   if(get_scroll_r() != 0) {
-    indent(out, indent_level) 
+    indent(out, indent_level + 2) 
       << "<Scalar> scroll_r { " << get_scroll_r() << " }\n";
 
   }
@@ -257,46 +257,46 @@ write(ostream &out, int indent_level) const {
   write_render_mode(out, indent_level + 2);
 
   if (get_portal_flag()) {
-    indent(out, indent_level) << "<Scalar> portal { 1 }\n";
+    indent(out, indent_level + 2) << "<Scalar> portal { 1 }\n";
   }
 
   if (get_occluder_flag()) {
-    indent(out, indent_level) << "<Scalar> occluder { 1 }\n";
+    indent(out, indent_level + 2) << "<Scalar> occluder { 1 }\n";
   }
 
   if (get_polylight_flag()) {
-    indent(out, indent_level) << "<Scalar> polylight { 1 }\n";
+    indent(out, indent_level + 2) << "<Scalar> polylight { 1 }\n";
   }
 
   if (has_indexed_flag()) {
-    indent(out, indent_level) 
+    indent(out, indent_level + 2) 
       << "<Scalar> indexed { " << get_indexed_flag() << " }\n";
   }
 
   if (get_blend_mode() != BM_unspecified) {
-    indent(out, indent_level)
+    indent(out, indent_level + 2)
       << "<Scalar> blend { " << get_blend_mode() << " }\n";
   }
 
   if (get_blend_operand_a() != BO_unspecified) {
-    indent(out, indent_level)
+    indent(out, indent_level + 2)
       << "<Scalar> blendop-a { " << get_blend_operand_a() << " }\n";
   }
 
   if (get_blend_operand_b() != BO_unspecified) {
-    indent(out, indent_level)
+    indent(out, indent_level + 2)
       << "<Scalar> blendop-b { " << get_blend_operand_b() << " }\n";
   }
 
   if (has_blend_color()) {
     const Colorf &c = get_blend_color();
-    indent(out, indent_level)
+    indent(out, indent_level + 2)
       << "<Scalar> blendr { " << c[0] << " }\n";
-    indent(out, indent_level)
+    indent(out, indent_level + 2)
       << "<Scalar> blendg { " << c[1] << " }\n";
-    indent(out, indent_level)
+    indent(out, indent_level + 2)
       << "<Scalar> blendb { " << c[2] << " }\n";
-    indent(out, indent_level)
+    indent(out, indent_level + 2)
       << "<Scalar> blenda { " << c[3] << " }\n";
   }
 

+ 4 - 0
panda/src/egg2pg/eggLoader.cxx

@@ -2648,6 +2648,10 @@ set_occluder_polygon(EggGroup *egg_group, OccluderNode *pnode) {
                           LCAST(float, v1),
                           LCAST(float, v2),
                           LCAST(float, v3));
+
+      if (poly->get_bface_flag()) {
+	pnode->set_double_sided(true);
+      }
     }
   }
 }

+ 11 - 8
panda/src/framework/pandaFramework.cxx

@@ -19,6 +19,7 @@
 #include "dataGraphTraverser.h"
 #include "depthOffsetAttrib.h"
 #include "collisionNode.h"
+#include "occluderNode.h"
 #include "config_framework.h"
 #include "graphicsPipeSelection.h"
 #include "nodePathCollection.h"
@@ -712,15 +713,16 @@ set_background_type(WindowFramework::BackgroundType type) {
 ////////////////////////////////////////////////////////////////////
 //     Function: PandaFramework::hide_collision_solids
 //       Access: Public
-//  Description: Hides any collision solids which are visible in the
-//               indicated scene graph.  Returns the number of
-//               collision solids hidden.
+//  Description: Hides any collision solids, or occluders, which are
+//               visible in the indicated scene graph.  Returns the
+//               number of nodes hidden.
 ////////////////////////////////////////////////////////////////////
 int PandaFramework::
 hide_collision_solids(NodePath node) {
   int num_changed = 0;
 
-  if (node.node()->is_of_type(CollisionNode::get_class_type())) {
+  if (node.node()->is_of_type(CollisionNode::get_class_type()) ||
+      node.node()->is_of_type(OccluderNode::get_class_type())) {
     if (!node.is_hidden()) {
       node.hide();
       num_changed++;
@@ -738,15 +740,16 @@ hide_collision_solids(NodePath node) {
 ////////////////////////////////////////////////////////////////////
 //     Function: PandaFramework::show_collision_solids
 //       Access: Public
-//  Description: Shows any collision solids which are directly hidden
-//               in the indicated scene graph.  Returns the number of
-//               collision solids shown.
+//  Description: Shows any collision solids, or occluders, which are
+//               directly hidden in the indicated scene graph.
+//               Returns the number of nodes shown.
 ////////////////////////////////////////////////////////////////////
 int PandaFramework::
 show_collision_solids(NodePath node) {
   int num_changed = 0;
 
-  if (node.node()->is_of_type(CollisionNode::get_class_type())) {
+  if (node.node()->is_of_type(CollisionNode::get_class_type()) ||
+      node.node()->is_of_type(OccluderNode::get_class_type())) {
     if (node.get_hidden_ancestor() == node) {
       node.show();
       num_changed++;

+ 59 - 7
panda/src/pgraph/cullPlanes.cxx

@@ -16,6 +16,7 @@
 #include "cullTraverserData.h"
 #include "clipPlaneAttrib.h"
 #include "occluderEffect.h"
+#include "boundingBox.h"
 
 
 ////////////////////////////////////////////////////////////////////
@@ -156,17 +157,48 @@ apply_state(const CullTraverser *trav, const CullTraverserData *data,
         }
 
         // Compare the occluder node's bounding volume to the view
-        // frustum.
-        PT(GeometricBoundingVolume) occluder_gbv = DCAST(GeometricBoundingVolume, occluder_node->get_internal_bounds()->make_copy());
-        {
-          CPT(TransformState) composed_transform = occluder_transform->compose(center_transform);
-          occluder_gbv->xform(composed_transform->get_mat());
+        // frustum.  We construct a new bounding volume because (a)
+        // the node's existing bounding volume is in the coordinate
+        // space of its parent, which isn't what we have here, and (b)
+        // 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;
 	  }
 	}
@@ -185,6 +217,10 @@ apply_state(const CullTraverser *trav, const CullTraverserData *data,
         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
@@ -192,7 +228,7 @@ apply_state(const CullTraverser *trav, const CullTraverserData *data,
         
         // Get the occluder geometry in cull-center space.
         const LMatrix4f &occluder_mat = occluder_transform->get_mat();
-        Vertexf points_near[4];
+        LPoint3f points_near[4];
         points_near[0] = occluder_node->get_vertex(0) * occluder_mat;
         points_near[1] = occluder_node->get_vertex(1) * occluder_mat;
         points_near[2] = occluder_node->get_vertex(2) * occluder_mat;
@@ -206,6 +242,10 @@ 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";
+	    }
             continue;
           }
         }
@@ -213,6 +253,10 @@ apply_state(const CullTraverser *trav, const CullTraverserData *data,
         float near_clip = scene->get_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";
+	  }
           continue;
         }
 
@@ -223,6 +267,10 @@ apply_state(const CullTraverser *trav, const CullTraverserData *data,
         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";
+	  }
           continue;
         }
 
@@ -232,11 +280,15 @@ apply_state(const CullTraverser *trav, const CullTraverserData *data,
         // proper fix for this is to clip the polygon against the near
         // plane, producing a smaller polygon, and use that to
         // generate the frustum.  But maybe it doesn't matter.  In
-        // lieu of this, we just toss out any polygon with *any*
+        // lieu of this, we just toss out any occluder with *any*
         // corner behind the y = 0 plane.
         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";
+	  }
           continue;
         }
 

+ 5 - 0
panda/src/pgraph/occluderNode.cxx

@@ -126,6 +126,11 @@ void OccluderNode::
 xform(const LMatrix4f &mat) {
   nassertv(!mat.is_nan());
 
+  for (Vertices::iterator vi = _vertices.begin();
+       vi != _vertices.end();
+       ++vi) {
+    (*vi) = (*vi) * mat;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////