From fd305329c77b63f1f124fbc673fe0228f7cf2bf8 Mon Sep 17 00:00:00 2001 From: David Rose Date: Mon, 28 Sep 2009 11:51:01 +0000 Subject: [PATCH] PortalNode contributions by Erik Pojar --- panda/src/pgraph/config_pgraph.cxx | 11 +- panda/src/pgraph/config_pgraph.h | 2 +- panda/src/pgraph/cullTraverser.cxx | 7 +- panda/src/pgraph/portalClipper.I | 54 ++++ panda/src/pgraph/portalClipper.cxx | 392 ++++++----------------------- panda/src/pgraph/portalClipper.h | 21 +- panda/src/pgraph/portalNode.cxx | 183 +++++++------- panda/src/pgraph/portalNode.h | 14 +- 8 files changed, 252 insertions(+), 432 deletions(-) diff --git a/panda/src/pgraph/config_pgraph.cxx b/panda/src/pgraph/config_pgraph.cxx index 72e8cb3643..52e9b86481 100644 --- a/panda/src/pgraph/config_pgraph.cxx +++ b/panda/src/pgraph/config_pgraph.cxx @@ -118,11 +118,12 @@ ConfigVariableBool allow_portal_cull "renderer to cull more objects that are clipped if not in the " "current list of portals. This is still somewhat experimental.")); -ConfigVariableBool show_portal_debug -("show-portal-debug", true, - PRC_DESC("Set this true to show debug lines for portals. This will draw " - "lines from the screen corners to the portal corners, this can " - "be useful when debugging.")); +ConfigVariableBool debug_portal_cull +("debug-portal-cull", false, + PRC_DESC("Set this true to enable debug visualization during portal clipping." + "(You first need to enable portal culling, using the allow-portal-cull" + "variable.)")); + ConfigVariableBool unambiguous_graph ("unambiguous-graph", false, diff --git a/panda/src/pgraph/config_pgraph.h b/panda/src/pgraph/config_pgraph.h index ce22448595..7ff27ab62b 100644 --- a/panda/src/pgraph/config_pgraph.h +++ b/panda/src/pgraph/config_pgraph.h @@ -33,7 +33,7 @@ NotifyCategoryDecl(portal, EXPCL_PANDA_PGRAPH, EXPTP_PANDA_PGRAPH); extern ConfigVariableBool fake_view_frustum_cull; extern ConfigVariableBool clip_plane_cull; extern ConfigVariableBool allow_portal_cull; -extern ConfigVariableBool show_portal_debug; +extern ConfigVariableBool debug_portal_cull; extern ConfigVariableBool unambiguous_graph; extern ConfigVariableBool detect_graph_cycles; extern ConfigVariableBool no_unsupported_copy; diff --git a/panda/src/pgraph/cullTraverser.cxx b/panda/src/pgraph/cullTraverser.cxx index fa984a6bb4..36d50c756a 100644 --- a/panda/src/pgraph/cullTraverser.cxx +++ b/panda/src/pgraph/cullTraverser.cxx @@ -121,7 +121,8 @@ traverse(const NodePath &root) { if (allow_portal_cull) { // This _view_frustum is in cull_center space - PT(GeometricBoundingVolume) vf = _view_frustum; + //Erik: obsolete? + //PT(GeometricBoundingVolume) vf = _view_frustum; GeometricBoundingVolume *local_frustum = NULL; PT(BoundingVolume) bv = _scene_setup->get_lens()->make_bounds(); @@ -133,7 +134,7 @@ traverse(const NodePath &root) { // This local_frustum is in camera space PortalClipper portal_viewer(local_frustum, _scene_setup); - if (show_portal_debug) { + if (debug_portal_cull) { portal_viewer.draw_camera_frustum(); } @@ -147,7 +148,7 @@ traverse(const NodePath &root) { traverse(data); // Finally add the lines to be drawn - if (show_portal_debug) { + if (debug_portal_cull) { portal_viewer.draw_lines(); } diff --git a/panda/src/pgraph/portalClipper.I b/panda/src/pgraph/portalClipper.I index 6cc90d5343..fbabb55f44 100755 --- a/panda/src/pgraph/portalClipper.I +++ b/panda/src/pgraph/portalClipper.I @@ -117,6 +117,56 @@ INLINE BoundingHexahedron *PortalClipper:: get_reduced_frustum() const { return _reduced_frustum; } + +//////////////////////////////////////////////////////////////////// +// Function: PortalClipper::set_clip_state +// Access: Public +// Description: Set the clip state of the current portal node +// This is done to remember the state for the child portal nodes +// +//////////////////////////////////////////////////////////////////// +INLINE void PortalClipper:: +set_clip_state(const RenderState* clip_state) { + _clip_state = clip_state; +} + +//////////////////////////////////////////////////////////////////// +// Function: PortalClipper::get_clip_state +// Access: Published +// Description: Returns the stored clip state +//////////////////////////////////////////////////////////////////// +INLINE const RenderState *PortalClipper:: +get_clip_state() const { + return _clip_state; +} + +//////////////////////////////////////////////////////////////////// +// Function: PortalClipper::set_reduced_viewport +// Access: Public +// Description: Set the current viewport that is being used +// by the portal clipper +// +//////////////////////////////////////////////////////////////////// +INLINE void PortalClipper:: +set_reduced_viewport(const LPoint2f& min, const LPoint2f& max) { + _reduced_viewport_min = min; + _reduced_viewport_max = max; +} + + +//////////////////////////////////////////////////////////////////// +// Function: PortalClipper::get_reduced_viewport +// Access: Published +// Description: Return the reduced viewport +//////////////////////////////////////////////////////////////////// +INLINE void PortalClipper:: +get_reduced_viewport(LPoint2f& min, LPoint2f& max) const { + min = _reduced_viewport_min; + max = _reduced_viewport_max; +} + + + //////////////////////////////////////////////////////////////////// // Function: PortalClipper::is_facing_view // Access: Public @@ -159,6 +209,7 @@ is_whole_portal_in_view(LMatrix4f cmat) { return (result != 0); } +/* //////////////////////////////////////////////////////////////////// // Function: PortalClipper::is_partial_portal_in_view // Access: Public @@ -178,7 +229,9 @@ is_partial_portal_in_view() { return (result != 0); } +*/ +/* //////////////////////////////////////////////////////////////////// // Function: PortalClipper::get_plane_depth // Access: Public @@ -199,3 +252,4 @@ get_plane_depth(float x, float z, Planef *portal_plane) { } return y; } +*/ \ No newline at end of file diff --git a/panda/src/pgraph/portalClipper.cxx b/panda/src/pgraph/portalClipper.cxx index 223f3d4c9b..774cd2869b 100755 --- a/panda/src/pgraph/portalClipper.cxx +++ b/panda/src/pgraph/portalClipper.cxx @@ -39,11 +39,16 @@ TypeHandle PortalClipper::_type_handle; // Description: //////////////////////////////////////////////////////////////////// PortalClipper:: -PortalClipper(GeometricBoundingVolume *frustum, SceneSetup *scene_setup) { +PortalClipper(GeometricBoundingVolume *frustum, SceneSetup *scene_setup): +_reduced_viewport_min(-1,-1), +_reduced_viewport_max(1,1), +_clip_state(0) +{ _previous = new GeomNode("my_frustum"); _view_frustum = _reduced_frustum = DCAST(BoundingHexahedron, frustum); + _scene_setup = scene_setup; } @@ -142,13 +147,13 @@ draw_current_portal() draw_to(_portal_node->get_vertex(2)); draw_to(_portal_node->get_vertex(3)); } + //////////////////////////////////////////////////////////////////// // Function: PortalClipper::draw the lines // Access: Public // Description: Draw all the lines in the buffer -// Yellow portal is the original geometry of the portal -// Cyan portal is the minmax adjusted portal -// Red portal is the clipped against frustum portal +// Cyan portal is the original geometry of the portal +// Yellow portal is the AA minmax & clipped portal // Blue frustum is the frustum through portal // White frustum is the camera frustum //////////////////////////////////////////////////////////////////// @@ -213,33 +218,19 @@ draw_lines() { // Description: Given the portal draw the frustum with line segs // for now. More functionalities coming up //////////////////////////////////////////////////////////////////// -void PortalClipper:: +bool PortalClipper:: prepare_portal(const NodePath &node_path) { - SegmentList segs; - // Get the Portal Node from this node_path PandaNode *node = node_path.node(); _portal_node = NULL; if (node->is_of_type(PortalNode::get_class_type())) { _portal_node = DCAST(PortalNode, node); - // lets draw the portal anyway - //draw_current_portal(); } - // walk the portal - _num_vert = 0; - // Get the geometry from the portal portal_cat.spam() << *_portal_node << endl; - /* - // Get the World transformation matrix - CPT(TransformState) wtransform = portal_nodepath.get_transform(_scene_setup->get_scene_root()); - LMatrix4f wmat = wtransform->get_mat(); - portal_cat.spam() << wmat << endl; - */ - // Get the camera transformation matrix CPT(TransformState) ctransform = node_path.get_transform(_scene_setup->get_cull_center()); //CPT(TransformState) ctransform = node_path.get_transform(_scene_setup->get_camera_path()); @@ -265,8 +256,8 @@ prepare_portal(const NodePath &node_path) Planef portal_plane(temp[0], temp[1], temp[2]); if (!is_facing_view(portal_plane)) { - portal_cat.debug() << "portal failed 1st level test \n"; - return; + portal_cat.debug() << "portal failed 1st level test (isn't facing the camera)\n"; + return false; } portal_cat.spam() << "after transformation to camera space" << endl; @@ -274,309 +265,92 @@ prepare_portal(const NodePath &node_path) portal_cat.spam() << temp[1] << endl; portal_cat.spam() << temp[2] << endl; portal_cat.spam() << temp[3] << endl; + + // check if the portal intersects with the cameras 0 point (center of projection). In that case the portal will invert itself. + // portals intersecting the near plane or the 0 point are a weird case anyhow, therefore we don't reduce the frustum any further + // and just return true. In effect the portal doesn't reduce visibility but will draw everything in its out cell + if ((temp[0][1] <= 0) || (temp[1][1] <= 0) || (temp[2][1] <= 0) || (temp[3][1] <= 0)) { + portal_cat.debug() << "portal intersects with center of projection.." << endl; + return true; + } - float min_x, max_x, min_z, max_z; + // project portal points, so they are in the -1..1 range + LPoint3f projected_coords[4]; + const Lens *lens = _scene_setup->get_lens(); + lens->project(temp[0], projected_coords[0]); + lens->project(temp[1], projected_coords[1]); + lens->project(temp[2], projected_coords[2]); + lens->project(temp[3], projected_coords[3]); - min_x = min(min(min(temp[0][0], temp[1][0]), temp[2][0]), temp[3][0]); - max_x = max(max(max(temp[0][0], temp[1][0]), temp[2][0]), temp[3][0]); - min_z = min(min(min(temp[0][2], temp[1][2]), temp[2][2]), temp[3][2]); - max_z = max(max(max(temp[0][2], temp[1][2]), temp[2][2]), temp[3][2]); + portal_cat.spam() << "after projection to 2d" << endl; + portal_cat.spam() << projected_coords[0] << endl; + portal_cat.spam() << projected_coords[1] << endl; + portal_cat.spam() << projected_coords[2] << endl; + portal_cat.spam() << projected_coords[3] << endl; - portal_cat.spam() << "min_x " << min_x << ";max_x " << max_x << ";min_z " << min_z << ";max_z " << max_z << endl; + // calculate axis aligned bounding box of the portal + float min_x, max_x, min_y, max_y; + min_x = min(min(min(projected_coords[0][0], projected_coords[1][0]), projected_coords[2][0]), projected_coords[3][0]); + max_x = max(max(max(projected_coords[0][0], projected_coords[1][0]), projected_coords[2][0]), projected_coords[3][0]); + min_y = min(min(min(projected_coords[0][1], projected_coords[1][1]), projected_coords[2][1]), projected_coords[3][1]); + max_y = max(max(max(projected_coords[0][1], projected_coords[1][1]), projected_coords[2][1]), projected_coords[3][1]); - float y; + portal_cat.spam() << "min_x " << min_x << ";max_x " << max_x << ";min_y " << min_y << ";max_y " << max_y << endl; - y = get_plane_depth(min_x, min_z, &portal_plane); - portal_cat.spam() << "plane's depth is " << y << endl; - _coords[0].set(min_x, y, min_z); + // clip the minima and maxima against the viewport + min_x = max(min_x, _reduced_viewport_min[0]); + min_y = max(min_y, _reduced_viewport_min[1]); + max_x = min(max_x, _reduced_viewport_max[0]); + max_y = min(max_y, _reduced_viewport_max[1]); - y = get_plane_depth(max_x, min_z, &portal_plane); - portal_cat.spam() << "plane's depth is " << y << endl; - _coords[1].set(max_x, y, min_z); + portal_cat.spam() << "after clipping: min_x " << min_x << ";max_x " << max_x << ";min_y " << min_y << ";max_y " << max_y << endl; - y = get_plane_depth(max_x, max_z, &portal_plane); - portal_cat.spam() << "plane's depth is " << y << endl; - _coords[2].set(max_x, y, max_z); + if ((min_x >= max_x) || (min_y >= max_y)) { + portal_cat.debug() << "portal got clipped away \n"; + return false; + } - y = get_plane_depth(min_x, max_z, &portal_plane); - portal_cat.spam() << "plane's depth is " << y << endl; - _coords[3].set(min_x, y, max_z); - - portal_cat.spam() << "after min max calculation" << endl; - portal_cat.spam() << _coords[0] << endl; - portal_cat.spam() << _coords[1] << endl; - portal_cat.spam() << _coords[2] << endl; - portal_cat.spam() << _coords[3] << endl; + // here we know the portal is in view and we have its clipped extents + _reduced_viewport_min.set(min_x, min_y); + _reduced_viewport_max.set(max_x, max_y); - // check if portal is in view - if (is_whole_portal_in_view(cmat)) { - // ok, now lets add the original portal + // calculate the near and far points so we can construct a frustum + LPoint3f near_point[4]; + LPoint3f far_point[4]; + lens->extrude(LPoint2f(min_x, min_y), near_point[0], far_point[0]); + lens->extrude(LPoint2f(max_x, min_y), near_point[1], far_point[1]); + lens->extrude(LPoint2f(max_x, max_y), near_point[2], far_point[2]); + lens->extrude(LPoint2f(min_x, max_y), near_point[3], far_point[3]); + + // With these points, construct the new reduced frustum + _reduced_frustum = new BoundingHexahedron(far_point[0], far_point[1], far_point[2], far_point[3], + near_point[0], near_point[1], near_point[2], near_point[3]); + + portal_cat.debug() << *_reduced_frustum << endl; + + // do debug rendering, if requested + if (debug_portal_cull) { + // draw the reduced frustum + _color = Colorf(0,0,1,1); + draw_hexahedron(DCAST(BoundingHexahedron, _reduced_frustum)); + + // lets first add the clipped portal (in yellow) + _color = Colorf(1,1,0,1); + move_to((near_point[0]+far_point[0])/2.0); // I choose a point in the middle between near and far.. could also be some other z value.. + draw_to((near_point[1]+far_point[1])/2.0); + draw_to((near_point[2]+far_point[2])/2.0); + draw_to((near_point[3]+far_point[3])/2.0); + draw_to((near_point[0]+far_point[0])/2.0); + + // ok, now lets add the original portal (in cyan) _color = Colorf(0,1,1,1); move_to(temp[0]); draw_to(temp[1]); draw_to(temp[2]); draw_to(temp[3]); draw_to(temp[0]); - - // ok, now lets add the min_max portal - _color = Colorf(1,1,0,1); - move_to(_coords[0]); - draw_to(_coords[1]); - draw_to(_coords[2]); - draw_to(_coords[3]); - draw_to(_coords[0]); - - portal_cat.spam() << "assembled " << _portal_node->get_name() << ": frustum points" << endl; - _num_vert = _portal_node->get_num_vertices(); } - else - portal_cat.debug() << "portal failed 2nd level test \n"; + + return true; } -//////////////////////////////////////////////////////////////////// -// Function: PortalClipper::clip the portal -// Access: Public -// Description: From the frustum clip the portal against the frustum -// and form the new planes of the reduced view frustum -//////////////////////////////////////////////////////////////////// -void PortalClipper:: -clip_portal(const NodePath &node_path) -{ - if (!_num_vert) - return; - - // ViewFrustum -> Logical Planes -> Portal Edge - // Plane0 -> far plane -> None - // plane5 -> near plane -> None - // Plane1 -> bottom plane -> 0-1 - // Plane3 -> top plane -> 1-2 - // Plane2 -> right plane -> 2-3 - // Plane4 -> left plane -> 3-0 - - int j; - float t; - Planef plane; - bool is_intersect; - unsigned int xect=0; - LPoint3f from_origin; - LPoint3f cut_point; - LVector3f from_direction; - - // Look for intersection with the view frustum's bottom_plane and portal edges - plane = _reduced_frustum->get_plane(1); - for (j=0; j<_num_vert; ++j) { - from_origin = _coords[j]; - 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)) { - xect |= 1 << 0; - portal_cat.debug() << "bottom plane intersected segment " << j << "->" - << (j+1)%_num_vert << " at t=" << t << endl; - cut_point = from_origin + t*from_direction; - portal_cat.spam() << "cut_point: " << cut_point << endl; - if (j == 1) { - // means bottom should cut 1->2 by moving 1 to the intersection point - _coords[1] = cut_point; - } - else if (j == 3) { - // means bottom should cut 3->0 by moving 0 to the intersection point - _coords[0] = cut_point; - } - else - portal_cat.debug() << "ignored for now for simplicity \n"; - } - else - portal_cat.spam() << "is_intersect: " << is_intersect << " at t = " << t << endl; - } - - // Look for intersection with the view frustum's top_plane and portal edges - plane = _reduced_frustum->get_plane(3); - for (j=0; j<_num_vert; ++j) { - from_origin = _coords[j]; - 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)) { - xect |= 1 << 1; - portal_cat.debug() << "top plane intersected segment " << j << "->" - << (j+1)%_num_vert << " at t=" << t << endl; - cut_point = from_origin + t*from_direction; - portal_cat.spam() << "cut_point: " << cut_point << endl; - if (j == 1) { - // means top should cut 1->2 by moving 2 to the intersection point - _coords[2] = cut_point; - } - else if (j == 3) { - // means top should cut 3->0 by moving 3 to the intersection point - _coords[3] = cut_point; - } - else - portal_cat.debug() << "ignored for now for simplicity \n"; - } - else - portal_cat.spam() << "is_intersect: " << is_intersect << " at t = " << t << endl; - } - - // Look for intersection with the view frustum's right_plane and portal edges - plane = _reduced_frustum->get_plane(2); - for (j=0; j<_num_vert; ++j) { - from_origin = _coords[j]; - 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)) { - xect |= 1 << 2; - portal_cat.debug() << "right plane intersected segment " << j << "->" - << (j+1)%_num_vert << " at t=" << t << endl; - cut_point = from_origin + t*from_direction; - portal_cat.spam() << "cut_point: " << cut_point << endl; - if (j == 0) { - // means right should cut 0->1 by moving 1 to the intersection point - _coords[1] = cut_point; - } - else if (j == 2) { - // means right should cut 2->3 by moving 2 to the intersection point - _coords[2] = cut_point; - } - else - portal_cat.debug() << "ignored for now for simplicity \n"; - } - else - portal_cat.spam() << "is_intersect: " << is_intersect << " at t = " << t << endl; - } - - // Look for intersection with the view frustum's left_plane and portal edges - plane = _reduced_frustum->get_plane(4); - for (j=0; j<_num_vert; ++j) { - from_origin = _coords[j]; - 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)) { - xect |= 1 << 3; - portal_cat.debug() << "left plane intersected segment " << j << "->" - << (j+1)%_num_vert << " at t=" << t << endl; - cut_point = from_origin + t*from_direction; - portal_cat.spam() << "cut_point: " << cut_point << endl; - if (j == 0) { - // means left should cut 0->1 by moving 0 to the intersection point - _coords[0] = cut_point; - } - else if (j == 2) { - // means left should cut 2->3 by moving 3 to the intersection point - _coords[3] = cut_point; - } - else - portal_cat.debug() << "ignored for now for simplicity \n"; - } - else - portal_cat.spam() << "is_intersect: " << is_intersect << " at t = " << t << endl; - } - // ok, now lets add the clipped portal - _color = Colorf(1,0,0,1); - move_to(_coords[0]); - draw_to(_coords[1]); - draw_to(_coords[2]); - draw_to(_coords[3]); - draw_to(_coords[0]); - - // 3rd level test, more accurate to determine if the portal is worth visiting - portal_cat.debug() << "portal clipper flag: " << xect << endl; - if (xect == 0xf) { //if all four planes intersected the portal, it is visible - return; - } - if (!is_partial_portal_in_view()) { - portal_cat.debug() << "portal failed 3rd level test \n"; - _num_vert = 0; - } -} - - -//////////////////////////////////////////////////////////////////// -// Function: PortalClipper::get_reduced_frustum -// Access: Public -// Description: After clipping the portal, form the new sides and -// fill in the new frustum. Return the new frustum -//////////////////////////////////////////////////////////////////// -PT(BoundingVolume) PortalClipper:: -get_reduced_frustum(const NodePath &node_path) -{ - // int num_planes = 6; - LPoint3f intersect_points[4]; - - // another approach to actually finding the points, so that - // I can reuse the current BoundingHexahedron object. Apparently, - // it is better to construct this BH with bounding points, rather - // than bounding planes (which I might have to implement soon) - - if (!_num_vert) - return NULL; - - float t; - bool visible = true; - - // find intersection of 7->3 with far - LPoint3f from_origin = _reduced_frustum->get_point(7); - LVector3f from_direction = _coords[3] - from_origin; - bool is_intersect = _reduced_frustum->get_plane(0).intersects_line(t, from_origin, from_direction); - if (is_intersect && t >= 0.0) { // has to be positive, else camera is not looking at the portal - portal_cat.spam() << "far plane intersected 7->3 at t=" << t << endl; - intersect_points[0] = from_origin + t*from_direction; - portal_cat.spam() << intersect_points[0] << endl; - } - else - visible = false; - - // find intersection of 4->0 with far - from_origin = _reduced_frustum->get_point(4); - from_direction = _coords[0] - from_origin; - is_intersect = _reduced_frustum->get_plane(0).intersects_line(t, from_origin, from_direction); - if (is_intersect && t >= 0.0) { // has to be positive, else camera is not looking at the portal - portal_cat.spam() << "far plane intersected 4->0 at t=" << t << endl; - intersect_points[1] = from_origin + t*from_direction; - portal_cat.spam() << intersect_points[1] << endl; - } - else - visible = false; - - // find intersection of 5->1 with far - from_origin = _reduced_frustum->get_point(5); - from_direction = _coords[1] - from_origin; - is_intersect = _reduced_frustum->get_plane(0).intersects_line(t, from_origin, from_direction); - if (is_intersect && t >= 0.0) { // has to be positive, else camera is not looking at the portal - portal_cat.spam() << "far plane intersected 5->1 at t=" << t << endl; - intersect_points[2] = from_origin + t*from_direction; - portal_cat.spam() << intersect_points[2] << endl; - } - else - visible = false; - - // find intersection of 6->2 with far - from_origin = _reduced_frustum->get_point(6); - from_direction = _coords[2] - from_origin; - is_intersect = _reduced_frustum->get_plane(0).intersects_line(t, from_origin, from_direction); - if (is_intersect && t >= 0.0) { // has to be positive, else camera is not looking at the portal - portal_cat.spam() << "far plane intersected 6->2 at t=" << t << endl; - intersect_points[3] = from_origin + t*from_direction; - portal_cat.spam() << intersect_points[3] << endl; - } - else - visible = false; - - if (!visible) { - portal_cat.spam() << "portal is not visible from current camera look at" << endl; - return NULL; - } - - // With these intersect_points, construct the new reduced frustum - PT(BoundingVolume) reduced_frustum = new - BoundingHexahedron(intersect_points[1], intersect_points[2], - intersect_points[3], intersect_points[0], - _reduced_frustum->get_point(4), _reduced_frustum->get_point(5), - _reduced_frustum->get_point(6), _reduced_frustum->get_point(7)); - - portal_cat.debug() << *reduced_frustum << endl; - - // draw this hexahedron - _color = Colorf(0,0,1,1); - draw_hexahedron(DCAST(BoundingHexahedron, reduced_frustum)); - - return reduced_frustum; -} diff --git a/panda/src/pgraph/portalClipper.h b/panda/src/pgraph/portalClipper.h index ed2c54cf2f..ee89637662 100755 --- a/panda/src/pgraph/portalClipper.h +++ b/panda/src/pgraph/portalClipper.h @@ -41,8 +41,6 @@ class CullTraverserData; class CullableObject; class NodePath; -//#define _FACING_THRESHOLD -0.7 //about 45 degrees with the camera -//#define _FACING_THRESHOLD -0.5 //about 60 degrees with the camera #define _FACING_THRESHOLD 0.0 //about 90 degrees with the camera //////////////////////////////////////////////////////////////////// @@ -62,10 +60,8 @@ public: INLINE bool is_facing_view(Planef portal_plane); INLINE bool is_whole_portal_in_view(LMatrix4f cmat); - void prepare_portal(const NodePath &node_path); - void clip_portal(const NodePath &node_path); - PT(BoundingVolume) get_reduced_frustum(const NodePath &node_path); - + bool prepare_portal(const NodePath &node_path); + void draw_lines(); INLINE void draw_camera_frustum(); void draw_hexahedron(BoundingHexahedron *frustum); @@ -78,10 +74,12 @@ public: void draw_current_portal(); - INLINE float get_plane_depth(float x, float z, Planef *portal_plane); - INLINE BoundingHexahedron *get_reduced_frustum() const; INLINE void set_reduced_frustum(BoundingHexahedron *bh); + INLINE void get_reduced_viewport(LPoint2f& min, LPoint2f& max) const; + INLINE void set_reduced_viewport(const LPoint2f& min, const LPoint2f& max); + INLINE const RenderState* get_clip_state() const; + INLINE void set_clip_state(const RenderState* clip_state); public: static TypeHandle get_class_type() { @@ -122,11 +120,14 @@ private: BoundingHexahedron *_view_frustum; BoundingHexahedron *_reduced_frustum; + LPoint2f _reduced_viewport_min; + LPoint2f _reduced_viewport_max; + CPT(RenderState) _clip_state; // each portal node needs to know the clip state of its "parent" portal Node PortalNode *_portal_node; // current working portal for dereference ease - int _num_vert; - Vertexf _coords[4]; + //int _num_vert; + //Vertexf _coords[4]; public: PT(GeomNode) _previous; diff --git a/panda/src/pgraph/portalNode.cxx b/panda/src/pgraph/portalNode.cxx index d064a6c94c..da286306f6 100755 --- a/panda/src/pgraph/portalNode.cxx +++ b/panda/src/pgraph/portalNode.cxx @@ -29,12 +29,6 @@ #include "plane.h" -/* -#ifndef CPPPARSER -#include "../collide/collisionPlane.h" -#endif -*/ - TypeHandle PortalNode::_type_handle; @@ -146,32 +140,21 @@ preserve_name() const { //////////////////////////////////////////////////////////////////// void PortalNode:: enable_clipping_planes() { + _top_plane_node = new PlaneNode("top"); + NodePath top_plane_np = NodePath(this).attach_new_node(_top_plane_node); + + _bottom_plane_node = new PlaneNode("bottom"); + NodePath bottom_plane_np = NodePath(this).attach_new_node(_bottom_plane_node); + _left_plane_node = new PlaneNode("left"); NodePath left_plane_np = NodePath(this).attach_new_node(_left_plane_node); _right_plane_node = new PlaneNode("right"); NodePath right_plane_np = NodePath(this).attach_new_node(_right_plane_node); - /* - // for debugging visialization, attach a collsion plane to left and right each - _left_coll_node = new CollisionNode("left_coll"); - _left_coll_node->set_into_collide_mask(CollideMask::all_off()); - // prepare a collision plane to be set later - PT(CollisionPlane) left_coll_plane = new CollisionPlane(Planef()); - _left_coll_node->add_solid(left_coll_plane); - // attach it onto the _left_plane_np - left_plane_np.attach_new_node(_left_coll_node); - - _right_coll_node = new CollisionNode("right_coll"); - _right_coll_node->set_into_collide_mask(CollideMask::all_off()); - // prepare a collision plane to be set later - PT(CollisionPlane) right_coll_plane = new CollisionPlane(Planef()); - _right_coll_node->add_solid(right_coll_plane); - // attach it onto the _left_plane_np - right_plane_np.attach_new_node(_right_coll_node); - */ - CPT(RenderAttrib) plane_attrib = ClipPlaneAttrib::make(); + plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib)->add_on_plane(NodePath(top_plane_np)); + plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib)->add_on_plane(NodePath(bottom_plane_np)); plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib)->add_on_plane(NodePath(left_plane_np)); plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib)->add_on_plane(NodePath(right_plane_np)); @@ -244,81 +227,97 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { PortalClipper *portal_viewer = trav->get_portal_clipper(); set_visible(false); if (is_open() && !_cell_out.is_empty() && portal_viewer) { - //CullTraverserData next_data(data, _cell_out); portal_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()))) { - set_visible(true); - // This reduced frustum is in camera space - portal_cat.debug() << "got reduced frustum " << reduced_frustum << endl; - vf = DCAST(GeometricBoundingVolume, reduced_frustum); - - // keep a copy of this reduced frustum - PT(BoundingHexahedron) new_bh = DCAST(BoundingHexahedron, vf->make_copy()); - - if (_clip_plane) { - // make a temp copy of this reduced frustum - PT(BoundingHexahedron) temp_bh = DCAST(BoundingHexahedron, vf->make_copy()); - CPT(TransformState) ftransform = - _cell_in.get_net_transform()->invert_compose(portal_viewer->_scene_setup->get_cull_center().get_net_transform()); + + // remember old viewport and frustum, so we can restore them for the siblings. (it gets changed by the prepare_portal call) + LPoint2f old_reduced_viewport_min, old_reduced_viewport_max; + portal_viewer->get_reduced_viewport(old_reduced_viewport_min, old_reduced_viewport_max); + PT(BoundingHexahedron) old_bh = portal_viewer->get_reduced_frustum(); - temp_bh->xform(ftransform->get_mat()); + if (portal_viewer->prepare_portal(data._node_path.get_node_path())) { + if ((reduced_frustum = portal_viewer->get_reduced_frustum())) { + // remember current clip state, we might change it + CPT(RenderState) old_clip_state = portal_viewer->get_clip_state(); + + set_visible(true); + // The frustum is in camera space + vf = DCAST(GeometricBoundingVolume, reduced_frustum); - // set left/right clipping plane - _left_plane_node->set_plane(-temp_bh->get_plane(4)); // left plane of bh - _right_plane_node->set_plane(-temp_bh->get_plane(2));// right plane of bh + // create a copy of this reduced frustum, we'll transform it from camera space to the cell_out space + PT(BoundingHexahedron) new_bh = DCAST(BoundingHexahedron, vf->make_copy()); + + // Get the net trasform of the _cell_out as seen from the camera. + CPT(TransformState) cell_transform = _cell_out.get_net_transform(); + CPT(TransformState) frustum_transform = cell_transform ->invert_compose(portal_viewer->_scene_setup->get_cull_center().get_net_transform()); - /* - // set this plane at the collision plane too for debugging - ((CollisionPlane*)_left_coll_node->get_solid(0))->set_plane(-temp_bh->get_plane(4)); - ((CollisionPlane*)_right_coll_node->get_solid(0))->set_plane(-temp_bh->get_plane(2)); - */ + // transform to _cell_out space + new_bh->xform(frustum_transform->get_mat()); + + CPT(RenderState) next_state = data._state; + + // set clipping planes, if desired.. + if (_clip_plane) { + // create a copy of this reduced frustum, we'll transform it from camera space to this portal node's space (because the clip planes are attached to this node) + PT(BoundingHexahedron) temp_bh = DCAST(BoundingHexahedron, vf->make_copy()); + CPT(TransformState) temp_frustum_transform = data._node_path.get_node_path().get_net_transform()->invert_compose(portal_viewer->_scene_setup->get_cull_center().get_net_transform()); + + portal_cat.spam() << "clipping plane frustum transform " << *temp_frustum_transform << endl; + portal_cat.spam() << "frustum before transform " << *temp_bh << endl; + // transform to portalNode space + temp_bh->xform(temp_frustum_transform->get_mat()); + + portal_cat.spam() << "frustum after transform " << *temp_bh << endl; + + _left_plane_node->set_plane(-temp_bh->get_plane(4)); // left plane of bh + _right_plane_node->set_plane(-temp_bh->get_plane(2));// right plane of bh + _top_plane_node->set_plane(-temp_bh->get_plane(3)); // top plane of bh + _bottom_plane_node->set_plane(-temp_bh->get_plane(1));// bottom plane of bh + + portal_cat.spam() << "left plane " << *_left_plane_node << endl; + portal_cat.spam() << "right plane " << *_right_plane_node << endl; + portal_cat.spam() << "top plane " << *_top_plane_node << endl; + portal_cat.spam() << "bottom plane " << *_bottom_plane_node << endl; + + // remember the clip state we just generated + portal_viewer->set_clip_state(_clip_state); + + if (old_clip_state) { + portal_cat.spam() << "parent clip state " << *old_clip_state << endl; + } else { + portal_cat.spam() << "parent clip state None" << endl; + } + portal_cat.spam() << "own clip state " << *_clip_state << endl; + portal_cat.spam() << "next state " << *next_state << endl; + + // undo parent clip state and compose our new clip state ito the new state + if (old_clip_state != NULL) { + next_state = old_clip_state->invert_compose(next_state); + portal_cat.spam() << "next state after removing parent state " << *next_state << endl; + } + next_state = next_state->compose(_clip_state); + portal_cat.spam() << "next state after composition " << *next_state << endl; + } + + CullTraverserData next_data(_cell_out, + cell_transform, + next_state, new_bh, + current_thread); + + portal_viewer->set_reduced_frustum(new_bh); + portal_cat.spam() << "cull_callback: before traversing " << _cell_out.get_name() << endl; + trav->traverse_below(next_data); + portal_cat.spam() << "cull_callback: after traversing " << _cell_out.get_name() << endl; + + // restore clip state + portal_viewer->set_clip_state(old_clip_state); } - - // Get the net trasform of the _cell_out as seen from the camera. - CPT(TransformState) cell_transform = - // trav->get_camera_transform()->invert_compose(_cell_out.get_net_transform()); - _cell_out.get_net_transform(); - - CPT(TransformState) frustum_transform = - _cell_out.get_net_transform()->invert_compose(portal_viewer->_scene_setup->get_cull_center().get_net_transform()); - - new_bh->xform(frustum_transform->get_mat()); - - portal_cat.spam() << "new_bh is " << *new_bh << "\n"; - - CPT(RenderState) next_state = data._state; - - // attach clipping state if there is any - if (_clip_plane) { - next_state = next_state->compose(_clip_state); - } - - CullTraverserData next_data(_cell_out, - cell_transform, - next_state, new_bh, - current_thread); - // data._state, new_bh, NULL); - - // Make this cell show with the reduced frustum - // _cell_out.show(); - // all nodes visible through this portal, should have this node's frustum - PT(BoundingHexahedron) old_bh = portal_viewer->get_reduced_frustum(); - portal_viewer->set_reduced_frustum(new_bh); - portal_cat.spam() << "cull_callback: before traversing " << _cell_out.get_name() << endl; - trav->traverse_below(next_data); - portal_cat.spam() << "cull_callback: after traversing " << _cell_out.get_name() << endl; - // make sure traverser is not drawing this node again - // _cell_out.hide(); - - // reset portal viewer frustum for the siblings; - portal_viewer->set_reduced_frustum(old_bh); } + // reset portal viewer frustum for the siblings; + portal_viewer->set_reduced_frustum(old_bh); + // reset portal viewer viewport for the siblings; + portal_viewer->set_reduced_viewport(old_reduced_viewport_min, old_reduced_viewport_max); } // Now carry on to render our child nodes. return true; diff --git a/panda/src/pgraph/portalNode.h b/panda/src/pgraph/portalNode.h index 07fa222e74..213325f0ce 100755 --- a/panda/src/pgraph/portalNode.h +++ b/panda/src/pgraph/portalNode.h @@ -23,12 +23,6 @@ #include "nodePath.h" #include "pvector.h" -/* -//#ifndef CPPPARSER -//#include "../collide/collisionSolid.h" -//#include "../collide/collisionNode.h" -//#endif -*/ //////////////////////////////////////////////////////////////////// // Class : PortalNode // Description : A node in the scene graph that can hold a @@ -121,15 +115,11 @@ private: NodePath _cell_out; // This is the cell it leads out to // enable plane clipping on this portal - /* -#ifndef CPPPARSER - PT(CollisionNode) _left_coll_node; // for debugging visualization - PT(CollisionNode) _right_coll_node;// for debugging visualization -#endif - */ bool _clip_plane; PT(PlaneNode) _left_plane_node; PT(PlaneNode) _right_plane_node; + PT(PlaneNode) _top_plane_node; + PT(PlaneNode) _bottom_plane_node; CPT(RenderState) _clip_state; bool _visible;