diff --git a/panda/src/mathutil/boundingHexahedron.cxx b/panda/src/mathutil/boundingHexahedron.cxx index 388985521e..2c2484585f 100644 --- a/panda/src/mathutil/boundingHexahedron.cxx +++ b/panda/src/mathutil/boundingHexahedron.cxx @@ -351,27 +351,32 @@ contains_box(const BoundingBox *box) const { float dist = p.dist_to_plane(center); float dist2 = dist * dist; - if (dist >= 0.0f && dist2 > radius2) { - // The sphere is completely in front of this plane; it's thus - // completely outside of the hexahedron. - return IF_no_intersection; - - } else if (dist < 0.0f && dist2 < radius2) { + if (dist2 <= radius2) { // The sphere is not completely behind this plane, but some of // it is. - + // Look a little closer. bool all_in = true; - for (int i = 0; i < 8 && all_in; ++i) { + bool all_out = true; + for (int i = 0; i < 8 && (all_in || all_out) ; ++i) { if (p.dist_to_plane(box->get_point(i)) < 0.0f) { + // This point is inside the plane. + all_out = false; + } else { // This point is outside the plane. all_in = false; } } - if (!all_in) { + if (all_out) { + return IF_no_intersection; + } else if (!all_in) { result &= ~IF_all; } + + } else if (dist >= 0.0f) { + // The sphere is completely in front of this plane. + return IF_no_intersection; } } diff --git a/panda/src/mathutil/boundingPlane.cxx b/panda/src/mathutil/boundingPlane.cxx index cff1756450..7e103856cd 100644 --- a/panda/src/mathutil/boundingPlane.cxx +++ b/panda/src/mathutil/boundingPlane.cxx @@ -173,27 +173,32 @@ contains_box(const BoundingBox *box) const { float dist = _plane.dist_to_plane(center); float dist2 = dist * dist; - if (dist >= 0.0f && dist2 > radius2) { - // The sphere is completely in front of this plane; it's thus - // completely outside of the hexahedron. - return IF_no_intersection; - - } else if (dist < 0.0f && dist2 < radius2) { + if (dist2 <= radius2) { // The sphere is not completely behind this plane, but some of // it is. // Look a little closer. bool all_in = true; - for (int i = 0; i < 8 && all_in; ++i) { + bool all_out = true; + for (int i = 0; i < 8 && (all_in || all_out) ; ++i) { if (_plane.dist_to_plane(box->get_point(i)) < 0.0f) { + // This point is inside the plane. + all_out = false; + } else { // This point is outside the plane. all_in = false; } } - if (!all_in) { + if (all_out) { + return IF_no_intersection; + } else if (!all_in) { result &= ~IF_all; } + + } else if (dist >= 0.0f) { + // The sphere is completely in front of this plane. + return IF_no_intersection; } return result; diff --git a/panda/src/pgraph/cullTraverser.cxx b/panda/src/pgraph/cullTraverser.cxx index b1676e2869..d0f00e7194 100644 --- a/panda/src/pgraph/cullTraverser.cxx +++ b/panda/src/pgraph/cullTraverser.cxx @@ -260,14 +260,55 @@ traverse_below(CullTraverserData &data) { GeomNode::Geoms geoms = geom_node->get_geoms(_current_thread); int num_geoms = geoms.get_num_geoms(); _geoms_pcollector.add_level(num_geoms); + CPT(TransformState) net_transform = data.get_net_transform(this); + CPT(TransformState) modelview_transform = data.get_modelview_transform(this); + CPT(TransformState) internal_transform = get_gsg()->get_cs_transform()->compose(modelview_transform); + for (int i = 0; i < num_geoms; i++) { - CullableObject *object = new CullableObject(this, data, geoms, i); - if (object->_state->has_cull_callback() && - !object->_state->cull_callback(this, data)) { - delete object; - } else { - _cull_handler->record_object(object, this); + const Geom *geom = geoms.get_geom(i); + + CPT(RenderState) state = data._state->compose(geoms.get_geom_state(i)); + if (state->has_cull_callback() && !state->cull_callback(this, data)) { + // Cull. + continue; } + + // Cull the Geom bounding volume against the view frustum + // and/or the cull planes. Don't bother unless we've got more + // than one Geom, since otherwise the bounding volume of the + // GeomNode is (probably) the same as that of the one Geom, + // and we've already culled against that. + if (num_geoms > 1) { + if (data._view_frustum != (GeometricBoundingVolume *)NULL) { + // Cull the individual Geom against the view frustum. + CPT(BoundingVolume) geom_volume = geom->get_bounds(); + const GeometricBoundingVolume *geom_gbv = + DCAST(GeometricBoundingVolume, geom_volume); + + int result = data._view_frustum->contains(geom_gbv); + if (result == BoundingVolume::IF_no_intersection) { + // Cull this Geom. + continue; + } + } + if (!data._cull_planes->is_empty()) { + // Also cull the Geom against the cull planes. + CPT(BoundingVolume) geom_volume = geom->get_bounds(); + const GeometricBoundingVolume *geom_gbv = + DCAST(GeometricBoundingVolume, geom_volume); + int result; + data._cull_planes->do_cull(result, state, geom_gbv); + if (result == BoundingVolume::IF_no_intersection) { + // Cull. + continue; + } + } + } + + CullableObject *object = + new CullableObject(geom, state, net_transform, + modelview_transform, internal_transform); + _cull_handler->record_object(object, this); } } @@ -365,6 +406,8 @@ is_in_view(CullTraverserData &data) { void CullTraverser:: show_bounds(CullTraverserData &data, bool tight) { PandaNode *node = data.node(); + CPT(TransformState) net_transform = data.get_net_transform(this); + CPT(TransformState) modelview_transform = data.get_modelview_transform(this); if (tight) { PT(Geom) bounds_viz = make_tight_bounds_viz(node); @@ -373,16 +416,24 @@ show_bounds(CullTraverserData &data, bool tight) { _geoms_pcollector.add_level(1); CullableObject *outer_viz = new CullableObject(bounds_viz, get_bounds_outer_viz_state(), - data.get_net_transform(this), - data.get_modelview_transform(this), + net_transform, modelview_transform, get_gsg()); _cull_handler->record_object(outer_viz, this); } } else { draw_bounding_volume(node->get_bounds(), - data.get_net_transform(this), - data.get_modelview_transform(this)); + net_transform, modelview_transform); + + if (node->is_geom_node()) { + // Also show the bounding volumes of included Geoms. + GeomNode *gnode = DCAST(GeomNode, node); + int num_geoms = gnode->get_num_geoms(); + for (int i = 0; i < num_geoms; ++i) { + draw_bounding_volume(gnode->get_geom(i)->get_bounds(), + net_transform, modelview_transform); + } + } } } @@ -673,16 +724,55 @@ start_decal(const CullTraverserData &data) { GeomNode::Geoms geoms = geom_node->get_geoms(); int num_geoms = geoms.get_num_geoms(); _geoms_pcollector.add_level(num_geoms); + CPT(TransformState) net_transform = data.get_net_transform(this); + CPT(TransformState) modelview_transform = data.get_modelview_transform(this); + CPT(TransformState) internal_transform = get_gsg()->get_cs_transform()->compose(modelview_transform); + for (int i = num_geoms - 1; i >= 0; i--) { - CullableObject *next_object = - new CullableObject(this, data, geoms, i, object); - if (next_object->_state->has_cull_callback() && - !next_object->_state->cull_callback(this, data)) { - next_object->_next = NULL; - delete next_object; - } else { - object = next_object; + const Geom *geom = geoms.get_geom(i); + + CPT(RenderState) state = data._state->compose(geoms.get_geom_state(i)); + if (state->has_cull_callback() && !state->cull_callback(this, data)) { + // Cull. + continue; } + + // Cull the Geom bounding volume against the view frustum + // and/or the cull planes. Don't bother unless we've got more + // than one Geom, since otherwise the bounding volume of the + // GeomNode is (probably) the same as that of the one Geom, + // and we've already culled against that. + if (num_geoms > 1) { + if (data._view_frustum != (GeometricBoundingVolume *)NULL) { + // Cull the individual Geom against the view frustum. + CPT(BoundingVolume) geom_volume = geom->get_bounds(); + const GeometricBoundingVolume *geom_gbv = + DCAST(GeometricBoundingVolume, geom_volume); + + int result = data._view_frustum->contains(geom_gbv); + if (result == BoundingVolume::IF_no_intersection) { + // Cull this Geom. + continue; + } + } + if (!data._cull_planes->is_empty()) { + // Also cull the Geom against the cull planes. + CPT(BoundingVolume) geom_volume = geom->get_bounds(); + const GeometricBoundingVolume *geom_gbv = + DCAST(GeometricBoundingVolume, geom_volume); + int result; + data._cull_planes->do_cull(result, state, geom_gbv); + if (result == BoundingVolume::IF_no_intersection) { + // Cull. + continue; + } + } + } + + object = + new CullableObject(geom, state, net_transform, + modelview_transform, internal_transform, + object); } if (object != separator) { @@ -743,16 +833,55 @@ r_get_decals(CullTraverserData &data, CullableObject *decals) { GeomNode::Geoms geoms = geom_node->get_geoms(); int num_geoms = geoms.get_num_geoms(); _geoms_pcollector.add_level(num_geoms); + CPT(TransformState) net_transform = data.get_net_transform(this); + CPT(TransformState) modelview_transform = data.get_modelview_transform(this); + CPT(TransformState) internal_transform = get_gsg()->get_cs_transform()->compose(modelview_transform); + for (int i = num_geoms - 1; i >= 0; i--) { - CullableObject *next_decals = - new CullableObject(this, data, geoms, i, decals); - if (next_decals->_state->has_cull_callback() && - !next_decals->_state->cull_callback(this, data)) { - next_decals->_next = NULL; - delete next_decals; - } else { - decals = next_decals; + const Geom *geom = geoms.get_geom(i); + + CPT(RenderState) state = data._state->compose(geoms.get_geom_state(i)); + if (state->has_cull_callback() && !state->cull_callback(this, data)) { + // Cull. + continue; } + + // Cull the Geom bounding volume against the view frustum + // and/or the cull planes. Don't bother unless we've got more + // than one Geom, since otherwise the bounding volume of the + // GeomNode is (probably) the same as that of the one Geom, + // and we've already culled against that. + if (num_geoms > 1) { + if (data._view_frustum != (GeometricBoundingVolume *)NULL) { + // Cull the individual Geom against the view frustum. + CPT(BoundingVolume) geom_volume = geom->get_bounds(); + const GeometricBoundingVolume *geom_gbv = + DCAST(GeometricBoundingVolume, geom_volume); + + int result = data._view_frustum->contains(geom_gbv); + if (result == BoundingVolume::IF_no_intersection) { + // Cull this Geom. + continue; + } + } + if (!data._cull_planes->is_empty()) { + // Also cull the Geom against the cull planes. + CPT(BoundingVolume) geom_volume = geom->get_bounds(); + const GeometricBoundingVolume *geom_gbv = + DCAST(GeometricBoundingVolume, geom_volume); + int result; + data._cull_planes->do_cull(result, state, geom_gbv); + if (result == BoundingVolume::IF_no_intersection) { + // Cull. + continue; + } + } + } + + decals = + new CullableObject(geom, state, net_transform, + modelview_transform, internal_transform, + decals); } } } diff --git a/panda/src/pgraph/cullableObject.I b/panda/src/pgraph/cullableObject.I index 5143dd20d1..1c3ca3e790 100644 --- a/panda/src/pgraph/cullableObject.I +++ b/panda/src/pgraph/cullableObject.I @@ -28,26 +28,6 @@ CullableObject(CullableObject *next) : { } -//////////////////////////////////////////////////////////////////// -// Function: CullableObject::Constructor -// Access: Public -// Description: Creates a CullableObject based on the ith Geom from -// the indicated GeomNode, with the render state from -// the indicated CullTraverserData. -//////////////////////////////////////////////////////////////////// -INLINE CullableObject:: -CullableObject(const CullTraverser *trav, const CullTraverserData &data, - const GeomNode::Geoms &geoms, int i, - CullableObject *next) : - _geom(geoms.get_geom(i)), - _state(data._state->compose(geoms.get_geom_state(i))), - _net_transform(data.get_net_transform(trav)), - _modelview_transform(data.get_modelview_transform(trav)), - _internal_transform(trav->get_gsg()->get_cs_transform()->compose(_modelview_transform)), - _next(next) -{ -} - //////////////////////////////////////////////////////////////////// // Function: CullableObject::Constructor // Access: Public @@ -68,6 +48,27 @@ CullableObject(const Geom *geom, const RenderState *state, _next(next) { } + +//////////////////////////////////////////////////////////////////// +// Function: CullableObject::Constructor +// Access: Public +// Description: Creates a CullableObject based the indicated geom, +// with the indicated render state and transform. +//////////////////////////////////////////////////////////////////// +INLINE CullableObject:: +CullableObject(const Geom *geom, const RenderState *state, + const TransformState *net_transform, + const TransformState *modelview_transform, + const TransformState *internal_transform, + CullableObject *next) : + _geom(geom), + _state(state), + _net_transform(net_transform), + _modelview_transform(modelview_transform), + _internal_transform(internal_transform), + _next(next) +{ +} //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/cullableObject.h b/panda/src/pgraph/cullableObject.h index 50ca812673..acb8522942 100644 --- a/panda/src/pgraph/cullableObject.h +++ b/panda/src/pgraph/cullableObject.h @@ -45,15 +45,16 @@ class CullTraverser; class EXPCL_PANDA CullableObject { public: INLINE CullableObject(CullableObject *next = NULL); - INLINE CullableObject(const CullTraverser *trav, - const CullTraverserData &data, - const GeomNode::Geoms &geoms, int i, - CullableObject *next = NULL); INLINE CullableObject(const Geom *geom, const RenderState *state, const TransformState *net_transform, const TransformState *modelview_transform, const GraphicsStateGuardianBase *gsg, CullableObject *next = NULL); + INLINE CullableObject(const Geom *geom, const RenderState *state, + const TransformState *net_transform, + const TransformState *modelview_transform, + const TransformState *internal_transform, + CullableObject *next = NULL); INLINE CullableObject(const CullableObject ©); INLINE void operator = (const CullableObject ©);