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

This commit is contained in:
David Rose 2011-03-18 19:02:46 +00:00
parent b099e2d063
commit 19d52c3221
6 changed files with 102 additions and 29 deletions

View File

@ -1320,6 +1320,15 @@ GROUPING ENTRIES
is constant-color or a related option, this defines the constant is constant-color or a related option, this defines the constant
color that will be used. 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 OTHER GROUP ATTRIBUTES

View File

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

View File

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

View File

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

View File

@ -16,6 +16,7 @@
#include "cullTraverserData.h" #include "cullTraverserData.h"
#include "clipPlaneAttrib.h" #include "clipPlaneAttrib.h"
#include "occluderEffect.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 // Compare the occluder node's bounding volume to the view
// frustum. // frustum. We construct a new bounding volume because (a)
PT(GeometricBoundingVolume) occluder_gbv = DCAST(GeometricBoundingVolume, occluder_node->get_internal_bounds()->make_copy()); // the node's existing bounding volume is in the coordinate
{ // space of its parent, which isn't what we have here, and (b)
CPT(TransformState) composed_transform = occluder_transform->compose(center_transform); // we might as well make a BoundingBox, which is as tight as
occluder_gbv->xform(composed_transform->get_mat()); // 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) { if (data->_view_frustum != (GeometricBoundingVolume *)NULL) {
int occluder_result = data->_view_frustum->contains(occluder_gbv); int occluder_result = data->_view_frustum->contains(occluder_gbv);
if (occluder_result == BoundingVolume::IF_no_intersection) { if (occluder_result == BoundingVolume::IF_no_intersection) {
// This occluder is outside the view frustum; ignore it. // 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; continue;
} }
} }
@ -185,6 +217,10 @@ apply_state(const CullTraverser *trav, const CullTraverserData *data,
if (is_enclosed) { if (is_enclosed) {
// No reason to add this occluder; it's behind an existing // No reason to add this occluder; it's behind an existing
// occluder. // occluder.
if (pgraph_cat.is_spam()) {
pgraph_cat.spam()
<< "Ignoring occluder " << occluder << ": behind another.\n";
}
continue; continue;
} }
// TODO: perhaps we should also check whether any existing // 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. // Get the occluder geometry in cull-center space.
const LMatrix4f &occluder_mat = occluder_transform->get_mat(); 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[0] = occluder_node->get_vertex(0) * occluder_mat;
points_near[1] = occluder_node->get_vertex(1) * occluder_mat; points_near[1] = occluder_node->get_vertex(1) * occluder_mat;
points_near[2] = occluder_node->get_vertex(2) * 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]); plane = Planef(points_near[0], points_near[1], points_near[2]);
} else { } else {
// This occluder is facing the wrong direction. Ignore it. // This occluder is facing the wrong direction. Ignore it.
if (pgraph_cat.is_spam()) {
pgraph_cat.spam()
<< "Ignoring occluder " << occluder << ": wrong direction.\n";
}
continue; continue;
} }
} }
@ -213,6 +253,10 @@ apply_state(const CullTraverser *trav, const CullTraverserData *data,
float near_clip = scene->get_lens()->get_near(); float near_clip = scene->get_lens()->get_near();
if (plane.dist_to_plane(LPoint3f::zero()) <= near_clip) { if (plane.dist_to_plane(LPoint3f::zero()) <= near_clip) {
// This occluder is behind the camera's near plane. Ignore it. // 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; 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) { if (d0 <= near_clip && d1 <= near_clip && d2 <= near_clip && d3 <= near_clip) {
// All four corners of the occluder are behind the camera's // All four corners of the occluder are behind the camera's
// near plane. Ignore it. // near plane. Ignore it.
if (pgraph_cat.is_spam()) {
pgraph_cat.spam()
<< "Ignoring occluder " << occluder << ": behind near plane (test 2).\n";
}
continue; 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 // proper fix for this is to clip the polygon against the near
// plane, producing a smaller polygon, and use that to // plane, producing a smaller polygon, and use that to
// generate the frustum. But maybe it doesn't matter. In // 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. // corner behind the y = 0 plane.
if (d0 <= 0.0 || d1 <= 0.0 || d2 <= 0.0 || d3 <= 0.0) { 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 // One of the corners is behind the y = 0 plane. We can't
// handle this case. Ignore it. // handle this case. Ignore it.
if (pgraph_cat.is_spam()) {
pgraph_cat.spam()
<< "Ignoring occluder " << occluder << ": partly behind zero plane.\n";
}
continue; continue;
} }

View File

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