瀏覽代碼

Recursive portal culling is implemented. This is the 3rd phase. There is one bug where portals are behaving weird when camera is right on the portal plane

Asad M. Zaman 21 年之前
父節點
當前提交
bd2a0ea086
共有 4 個文件被更改,包括 72 次插入52 次删除
  1. 33 13
      panda/src/pgraph/portalClipper.I
  2. 12 13
      panda/src/pgraph/portalClipper.cxx
  3. 5 6
      panda/src/pgraph/portalClipper.h
  4. 22 20
      panda/src/pgraph/portalNode.cxx

+ 33 - 13
panda/src/pgraph/portalClipper.I

@@ -101,24 +101,43 @@ draw_camera_frustum() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: PortalClipper::set_reduced_frustum
+//     Function: PortalClipper::set_view_frustum
 //       Access: Public
-//  Description: set the current reduced frustum before traversing
+//  Description: set the current view frustum before traversing
 //           
 ////////////////////////////////////////////////////////////////////
 INLINE void PortalClipper::
-set_reduced_frustum(BoundingHexahedron *frustum) {
-  _reduced_frustum = frustum;
+set_view_frustum(BoundingHexahedron *frustum) {
+  _view_frustum = frustum;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: PortalClipper::is_facing_view
+//       Access: Public
+//  Description: checks if the portal plane (in camera space)
+//               is facing the camera's near plane
+////////////////////////////////////////////////////////////////////
+INLINE bool PortalClipper::
+is_facing_view(Planef portal_plane)
+{
+  Planef view_plane(_view_frustum->get_point(4), _view_frustum->get_point(5), _view_frustum->get_point(6));
+
+  // use the view_frustum's near plane to calculate direction
+  pgraph_cat.debug() << portal_plane.get_normal() << "; " << -view_plane.get_normal() << endl;
+  float direction = portal_plane.get_normal().dot(-view_plane.get_normal());
+  pgraph_cat.debug() << "Found direction of " << direction << endl;
+  return (direction < _FACING_THRESHOLD);
+}
+
 ////////////////////////////////////////////////////////////////////
-//     Function: PortalClipper::is_in_view
+//     Function: PortalClipper::is_whole_portal_in_view
 //       Access: Public
 //  Description: checks if portal_node is within the view frustum.
 //               If so, then the portal is worth considering. This
 //               is a 1st level test to weed out most of the portals
 ////////////////////////////////////////////////////////////////////
 INLINE bool PortalClipper::
-is_in_view(const NodePath &node_path) {
+is_whole_portal_in_view(const NodePath &node_path) {
 
   const BoundingVolume *bv = &_portal_node->get_bound();
 
@@ -130,27 +149,28 @@ is_in_view(const NodePath &node_path) {
   CPT(TransformState) ctransform = node_path.get_transform(_scene_setup->get_cull_center());
   gbv->xform(ctransform->get_mat());
 
-  int result = _reduced_frustum->contains(gbv);
-  pgraph_cat.debug() << "1st level test if portal is in view " << result << endl;
+  int result = _view_frustum->contains(gbv);
+
+  pgraph_cat.debug() << "1st level test if portal: " << *_view_frustum << " is in view " << result << endl;
   return (result != 0);
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: PortalClipper::facing_camera
+//     Function: PortalClipper::is_partial_portal_in_view
 //       Access: Public
 //  Description: checks if any of the _coords is within the view frustum.
 //               If so, then the portal is facing the camera. 2nd level
 //               test to make sure this portal is worth visiting
 ////////////////////////////////////////////////////////////////////
 INLINE bool PortalClipper::
-is_facing_camera(const NodePath &node_path) {
+is_partial_portal_in_view(const NodePath &node_path) {
   int result = 0;
 
-  // check if the camera_center to portal_center lineseg is in view
+  // check if any of the _coords in tested frustum
   for (int j=0; j<_num_vert; ++j) {
-    result |= _reduced_frustum->contains(_coords[j]);
+    result |= _view_frustum->contains(_coords[j]);
   }
-  pgraph_cat.debug() << "frustum->contains(coord) result = " << result << endl;
+  pgraph_cat.debug() << "frustum: " << *_view_frustum << " contains(coord) result = " << result << endl;
 
   return (result != 0);
 }

+ 12 - 13
panda/src/pgraph/portalClipper.cxx

@@ -47,7 +47,7 @@ PortalClipper(GeometricBoundingVolume *frustum, SceneSetup *scene_setup) {
   _geom_point = new GeomPoint;
   _geom_linestrip = new GeomLinestrip;
 
-  _view_frustum = _reduced_frustum = DCAST(BoundingHexahedron, frustum);
+  _view_frustum = DCAST(BoundingHexahedron, frustum);
 
   _scene_setup = scene_setup;
 }
@@ -260,6 +260,10 @@ prepare_portal(const NodePath &node_path)
   temp[2] = temp[2]*cmat;
   temp[3] = temp[3]*cmat;
 
+  Planef portal_plane(temp[0], temp[1], temp[2]);
+  if (!is_facing_view(portal_plane))
+    return;
+
   pgraph_cat.spam() << "after transformation to camera space" << endl;
   pgraph_cat.spam() << temp[0] << endl;
   pgraph_cat.spam() << temp[1] << endl;
@@ -275,9 +279,6 @@ prepare_portal(const NodePath &node_path)
 
   pgraph_cat.spam() << "min_x " << min_x << ";max_x " << max_x << ";min_z " << min_z << ";max_z " << max_z << endl;
 
-
-  Planef portal_plane(temp[0], temp[1], temp[2]);
-
   float y;
 
   y = get_plane_depth(min_x, min_z, &portal_plane);
@@ -303,7 +304,7 @@ prepare_portal(const NodePath &node_path)
   pgraph_cat.spam() << _coords[3] << endl;
 
   // check if portal is in view
-  if (is_in_view(node_path)) {
+  if (is_whole_portal_in_view(node_path)) {
     pgraph_cat.debug() << "portal passed 1st level test \n";
     
     // ok, now lets add the original portal
@@ -376,7 +377,7 @@ clip_portal(const NodePath &node_path)
     from_direction = _coords[(j+1)%_num_vert] - _coords[j];
     is_intersect = plane.intersects_line(t, from_origin, from_direction);
     if (is_intersect && (t > 0.0 && t < 1.0)) {
-      pgraph_cat.debug() << "bottom plane intersected segement " << j << "->" 
+      pgraph_cat.debug() << "bottom plane intersected segment " << j << "->" 
                          << (j+1)%_num_vert << " at t=" << t << endl;
       cut_point = from_origin + t*from_direction;
       pgraph_cat.debug() << "cut_point: " << cut_point << endl;
@@ -400,7 +401,7 @@ clip_portal(const NodePath &node_path)
     from_direction = _coords[(j+1)%_num_vert] - _coords[j];
     is_intersect = plane.intersects_line(t, from_origin, from_direction);
     if (is_intersect && (t > 0.0 && t < 1.0)) {
-      pgraph_cat.debug() << "top plane intersected segement " << j << "->" 
+      pgraph_cat.debug() << "top plane intersected segment " << j << "->" 
                          << (j+1)%_num_vert << " at t=" << t << endl;
       cut_point = from_origin + t*from_direction;
       pgraph_cat.debug() << "cut_point: " << cut_point << endl;
@@ -424,7 +425,7 @@ clip_portal(const NodePath &node_path)
     from_direction = _coords[(j+1)%_num_vert] - _coords[j];
     is_intersect = plane.intersects_line(t, from_origin, from_direction);
     if (is_intersect && (t > 0.0 && t < 1.0)) {
-      pgraph_cat.debug() << "right plane intersected segement " << j << "->" 
+      pgraph_cat.debug() << "right plane intersected segment " << j << "->" 
                          << (j+1)%_num_vert << " at t=" << t << endl;
       cut_point = from_origin + t*from_direction;
       pgraph_cat.debug() << "cut_point: " << cut_point << endl;
@@ -448,7 +449,7 @@ clip_portal(const NodePath &node_path)
     from_direction = _coords[(j+1)%_num_vert] - _coords[j];
     is_intersect = plane.intersects_line(t, from_origin, from_direction);
     if (is_intersect && (t > 0.0 && t < 1.0)) {
-      pgraph_cat.debug() << "left plane intersected segement " << j << "->" 
+      pgraph_cat.debug() << "left plane intersected segment " << j << "->" 
                          << (j+1)%_num_vert << " at t=" << t << endl;
       cut_point = from_origin + t*from_direction;
       pgraph_cat.debug() << "cut_point: " << cut_point << endl;
@@ -473,7 +474,7 @@ clip_portal(const NodePath &node_path)
   draw_to(_coords[0]);
 
   // 2nd level test, more accurate to determine if the portal is worth visiting
-  if (!is_facing_camera(node_path)) {
+  if (!is_partial_portal_in_view(node_path)) {
     pgraph_cat.debug() << "portal failed 2nd level test \n";
     _num_vert = 0;
   }
@@ -562,13 +563,11 @@ get_reduced_frustum(const NodePath &node_path)
                        _view_frustum->get_point(4), _view_frustum->get_point(5),
                        _view_frustum->get_point(6), _view_frustum->get_point(7));
 
-  pgraph_cat.spam() << *reduced_frustum << endl;
+  pgraph_cat.debug() << *reduced_frustum << endl;
 
   // draw this hexahedron
   _color = Colorf(0,0,1,1);
   draw_hexahedron(DCAST(BoundingHexahedron, reduced_frustum));
 
-  _reduced_frustum = DCAST(BoundingHexahedron, reduced_frustum);
-
   return reduced_frustum;
 }

+ 5 - 6
panda/src/pgraph/portalClipper.h

@@ -63,12 +63,12 @@ public:
   PortalClipper(GeometricBoundingVolume *frustum, SceneSetup *scene_setup);
   ~PortalClipper();
 
-  INLINE bool is_in_view(const NodePath &node_path);
-  INLINE bool is_facing_camera(const NodePath &node_path);
-  void prepare_portal(const NodePath &node_path);
+  INLINE bool is_whole_portal_in_view(const NodePath &node_path);
+  INLINE bool is_partial_portal_in_view(const NodePath &node_path);
+  INLINE bool is_facing_view(Planef portal_plane);
 
+  void prepare_portal(const NodePath &node_path);
   void clip_portal(const NodePath &node_path);
-
   PT(BoundingVolume) get_reduced_frustum(const NodePath &node_path);
 
   void draw_lines();
@@ -83,7 +83,7 @@ public:
 
   INLINE float get_plane_depth(float x, float z, Planef *portal_plane);
 
-  INLINE void  set_reduced_frustum(BoundingHexahedron *frustum);
+  INLINE void  set_view_frustum(BoundingHexahedron *frustum);
 
 public:
   static TypeHandle get_class_type() {
@@ -129,7 +129,6 @@ private:
   PT(GeomLinestrip) _geom_linestrip;
 
   BoundingHexahedron *_view_frustum;
-  BoundingHexahedron *_reduced_frustum;
 
   PortalNode *_portal_node;  // current working portal for dereference ease
 

+ 22 - 20
panda/src/pgraph/portalNode.cxx

@@ -48,7 +48,7 @@ PortalNode(const string &name) :
 {
   _zone_in = NULL;
   _zone_out = NULL;
-  _visible = false;
+  _visible = true;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -65,7 +65,7 @@ PortalNode(const PortalNode &copy) :
 {
   _zone_in = NULL;
   _zone_out = NULL;
-  _visible = false;
+  _visible = true;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -180,28 +180,30 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
   PortalClipper *portal_viewer = trav->get_portal_clipper();
   if (!_zone_out.is_empty() && portal_viewer) {
     //CullTraverserData next_data(data, _zone_out);
-    if (is_visible()) {
-      pgraph_cat.debug() << "portal node visible " << *this << endl;
-      PT(GeometricBoundingVolume) vf = trav->get_view_frustum();
-      PT(BoundingVolume) reduced_frustum;
+    pgraph_cat.debug() << "checking portal node  " << *this << endl;
+    PT(GeometricBoundingVolume) vf = trav->get_view_frustum();
+    PT(BoundingVolume) reduced_frustum;
+     
+    // following three functions do nothing, if the portal is not visible
+    portal_viewer->prepare_portal(data._node_path.get_node_path());
+    portal_viewer->clip_portal(data._node_path.get_node_path());
+    if ((reduced_frustum = portal_viewer->get_reduced_frustum(data._node_path.get_node_path()))) {
+      // This reduced frustum is in camera space
+      pgraph_cat.debug() << "got reduced frustum " << reduced_frustum << endl;
+      vf = DCAST(GeometricBoundingVolume, reduced_frustum);
+      
+      portal_viewer->set_view_frustum(DCAST(BoundingHexahedron,vf->make_copy()));
+      
+      // trasform it to cull_center space
+      CPT(TransformState) cull_center_transform = 
+        portal_viewer->_scene_setup->get_cull_center().get_transform(_zone_out);
+      vf->xform(cull_center_transform->get_mat());
       
-      portal_viewer->prepare_portal(data._node_path.get_node_path());
-      portal_viewer->clip_portal(data._node_path.get_node_path());
-      if ((reduced_frustum = portal_viewer->get_reduced_frustum(data._node_path.get_node_path()))) {
-        // This reduced frustum is in camera space
-        pgraph_cat.debug() << "got reduced frustum " << reduced_frustum << endl;
-        vf = DCAST(GeometricBoundingVolume, reduced_frustum);
-        
-        // trasform it to cull_center space
-        CPT(TransformState) cull_center_transform = 
-          portal_viewer->_scene_setup->get_cull_center().get_transform(_zone_out);
-        vf->xform(cull_center_transform->get_mat());
-      }
       pgraph_cat.spam() << "vf is " << *vf << "\n";
-
+    
       // Get the net trasform of the _zone_out
       CPT(TransformState) zone_transform = _zone_out.get_net_transform();
-
+      
       CullTraverserData next_data(_zone_out, trav->get_render_transform()->compose(zone_transform),
                                   zone_transform,
                                   trav->get_initial_state(), vf,