cull to geoms; fix box culling

This commit is contained in:
David Rose 2007-06-04 20:18:57 +00:00
parent 1ca36eedd9
commit fe951a35fd
5 changed files with 208 additions and 67 deletions

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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)
{
}
////////////////////////////////////////////////////////////////////

View File

@ -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 &copy);
INLINE void operator = (const CullableObject &copy);