From 19d52c32216a2e5bdaf9f7d156e16ad90682563d Mon Sep 17 00:00:00 2001 From: David Rose Date: Fri, 18 Mar 2011 19:02:46 +0000 Subject: [PATCH] fix problem with local transform on occluder; add egg bface support for occluders --- panda/src/doc/eggSyntax.txt | 9 ++++ panda/src/egg/eggGroup.cxx | 28 +++++------ panda/src/egg2pg/eggLoader.cxx | 4 ++ panda/src/framework/pandaFramework.cxx | 19 ++++---- panda/src/pgraph/cullPlanes.cxx | 66 +++++++++++++++++++++++--- panda/src/pgraph/occluderNode.cxx | 5 ++ 6 files changed, 102 insertions(+), 29 deletions(-) diff --git a/panda/src/doc/eggSyntax.txt b/panda/src/doc/eggSyntax.txt index 8e3002f502..82320fa15f 100644 --- a/panda/src/doc/eggSyntax.txt +++ b/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. + 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 diff --git a/panda/src/egg/eggGroup.cxx b/panda/src/egg/eggGroup.cxx index 7526a60935..9d0903e9fa 100644 --- a/panda/src/egg/eggGroup.cxx +++ b/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) << " scroll_u { " << get_scroll_u() << " }\n"; } if(get_scroll_v() != 0) { - indent(out, indent_level) + indent(out, indent_level + 2) << " scroll_v { " << get_scroll_v() << " }\n"; } if(get_scroll_r() != 0) { - indent(out, indent_level) + indent(out, indent_level + 2) << " 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) << " portal { 1 }\n"; + indent(out, indent_level + 2) << " portal { 1 }\n"; } if (get_occluder_flag()) { - indent(out, indent_level) << " occluder { 1 }\n"; + indent(out, indent_level + 2) << " occluder { 1 }\n"; } if (get_polylight_flag()) { - indent(out, indent_level) << " polylight { 1 }\n"; + indent(out, indent_level + 2) << " polylight { 1 }\n"; } if (has_indexed_flag()) { - indent(out, indent_level) + indent(out, indent_level + 2) << " indexed { " << get_indexed_flag() << " }\n"; } if (get_blend_mode() != BM_unspecified) { - indent(out, indent_level) + indent(out, indent_level + 2) << " blend { " << get_blend_mode() << " }\n"; } if (get_blend_operand_a() != BO_unspecified) { - indent(out, indent_level) + indent(out, indent_level + 2) << " blendop-a { " << get_blend_operand_a() << " }\n"; } if (get_blend_operand_b() != BO_unspecified) { - indent(out, indent_level) + indent(out, indent_level + 2) << " 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) << " blendr { " << c[0] << " }\n"; - indent(out, indent_level) + indent(out, indent_level + 2) << " blendg { " << c[1] << " }\n"; - indent(out, indent_level) + indent(out, indent_level + 2) << " blendb { " << c[2] << " }\n"; - indent(out, indent_level) + indent(out, indent_level + 2) << " blenda { " << c[3] << " }\n"; } diff --git a/panda/src/egg2pg/eggLoader.cxx b/panda/src/egg2pg/eggLoader.cxx index e8b3809999..c468222de0 100644 --- a/panda/src/egg2pg/eggLoader.cxx +++ b/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); + } } } } diff --git a/panda/src/framework/pandaFramework.cxx b/panda/src/framework/pandaFramework.cxx index cfb039e213..bbb764ca68 100644 --- a/panda/src/framework/pandaFramework.cxx +++ b/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++; diff --git a/panda/src/pgraph/cullPlanes.cxx b/panda/src/pgraph/cullPlanes.cxx index 5d234c25ef..825680e3b0 100644 --- a/panda/src/pgraph/cullPlanes.cxx +++ b/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; } diff --git a/panda/src/pgraph/occluderNode.cxx b/panda/src/pgraph/occluderNode.cxx index d259cd3c46..573761ecdb 100644 --- a/panda/src/pgraph/occluderNode.cxx +++ b/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; + } } ////////////////////////////////////////////////////////////////////