mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-02 09:52:27 -04:00
pgraph bounding volumes
This commit is contained in:
parent
5a7b991858
commit
168c647d05
@ -98,6 +98,8 @@ public:
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
|
||||
friend class PandaNode;
|
||||
};
|
||||
|
||||
#ifndef DONT_INLINE_GRAPH
|
||||
|
@ -19,10 +19,10 @@
|
||||
#ifndef BOUNDINGVOLUME_H
|
||||
#define BOUNDINGVOLUME_H
|
||||
|
||||
#include <pandabase.h>
|
||||
#include "pandabase.h"
|
||||
|
||||
#include <typedObject.h>
|
||||
#include <typedReferenceCount.h>
|
||||
#include "typedObject.h"
|
||||
#include "typedReferenceCount.h"
|
||||
|
||||
class BoundingSphere;
|
||||
class BoundingHexahedron;
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include "cullBinBackToFront.h"
|
||||
#include "graphicsStateGuardianBase.h"
|
||||
#include "geometricBoundingVolume.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@ -33,14 +34,22 @@ TypeHandle CullBinBackToFront::_type_handle;
|
||||
void CullBinBackToFront::
|
||||
add_geom(Geom *geom, const TransformState *transform,
|
||||
const RenderState *state) {
|
||||
// Since we don't have bounding volumes yet, for now we'll just use
|
||||
// the origin of the node. Only accurate for local transforms.
|
||||
const LMatrix4f &mat = transform->get_mat();
|
||||
const LVecBase3f &pos = mat.get_row3(3);
|
||||
// Determine the center of the bounding volume.
|
||||
const BoundingVolume &volume = geom->get_bound();
|
||||
|
||||
// Oops! Don't have compute_distance_to() here either!
|
||||
float dist = -pos[2];
|
||||
_geoms.push_back(GeomData(geom, transform, state, dist));
|
||||
if (!volume.is_empty() &&
|
||||
volume.is_of_type(GeometricBoundingVolume::get_class_type())) {
|
||||
const GeometricBoundingVolume *gbv;
|
||||
DCAST_INTO_V(gbv, &volume);
|
||||
|
||||
LPoint3f center = gbv->get_approx_center();
|
||||
center = center * transform->get_mat();
|
||||
|
||||
// Oops! Don't have compute_distance_to() here yet!
|
||||
// float distance = gsg->compute_distance_to(center);
|
||||
float distance = -center[2];
|
||||
_geoms.push_back(GeomData(geom, transform, state, distance));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -341,6 +341,7 @@ INLINE void PandaNode::
|
||||
set_transform(const TransformState *transform) {
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_transform = transform;
|
||||
mark_bound_stale();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -391,6 +392,71 @@ ls(ostream &out, int indent_level) const {
|
||||
r_list_descendants(out, indent_level);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::set_bound
|
||||
// Access: Published
|
||||
// Description: Sets the type of the external bounding volume that is
|
||||
// placed around this node and all of its children.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PandaNode::
|
||||
set_bound(BoundingVolumeType type) {
|
||||
BoundedObject::set_bound(type);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::set_bound
|
||||
// Access: Published
|
||||
// Description: Resets the internal bounding volume so that it is the
|
||||
// indicated volume. The external bounding volume as
|
||||
// returned by get_bound() (which includes all of the
|
||||
// node's children) will be adjusted to include this
|
||||
// internal volume.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PandaNode::
|
||||
set_bound(const BoundingVolume &volume) {
|
||||
_internal_bound.set_bound(volume);
|
||||
changed_internal_bound();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::get_bound
|
||||
// Access: Published
|
||||
// Description: Returns the node's external bounding volume. This is
|
||||
// the bounding volume around the node and all of its
|
||||
// children.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const BoundingVolume &PandaNode::
|
||||
get_bound() const {
|
||||
return BoundedObject::get_bound();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::get_internal_bound
|
||||
// Access: Published
|
||||
// Description: Returns the node's internal bounding volume. This is
|
||||
// the bounding volume around the node alone, without
|
||||
// including children.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const BoundingVolume &PandaNode::
|
||||
get_internal_bound() const {
|
||||
if (_internal_bound.is_bound_stale()) {
|
||||
((PandaNode *)this)->recompute_internal_bound();
|
||||
}
|
||||
return _internal_bound.get_bound();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::changed_internal_bound
|
||||
// Access: Protected
|
||||
// Description: Should be called whenever you adjust the
|
||||
// _internal_bound member, to force the external
|
||||
// bounding volume to be recomputed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PandaNode::
|
||||
changed_internal_bound() {
|
||||
BoundedObject::mark_bound_stale();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::get_children
|
||||
// Access: Public
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "bamReader.h"
|
||||
#include "bamWriter.h"
|
||||
#include "indent.h"
|
||||
#include "geometricBoundingVolume.h"
|
||||
|
||||
|
||||
TypeHandle PandaNode::_type_handle;
|
||||
@ -37,8 +38,6 @@ CData(const PandaNode::CData ©) :
|
||||
_down(copy._down),
|
||||
_up(copy._up),
|
||||
_chains(copy._chains),
|
||||
_node_bounds(copy._node_bounds),
|
||||
_subgraph_bounds(copy._subgraph_bounds),
|
||||
_state(copy._state),
|
||||
_transform(copy._transform)
|
||||
{
|
||||
@ -93,12 +92,11 @@ PandaNode(const PandaNode ©) :
|
||||
{
|
||||
// Copying a node does not copy its children.
|
||||
|
||||
// Copy the other node's state and bounding volume.
|
||||
// Copy the other node's state.
|
||||
CDReader copy_cdata(copy._cycler);
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_state = copy_cdata->_state;
|
||||
cdata->_transform = copy_cdata->_transform;
|
||||
cdata->_node_bounds = copy_cdata->_node_bounds;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -112,12 +110,11 @@ operator = (const PandaNode ©) {
|
||||
Namable::operator = (copy);
|
||||
ReferenceCount::operator = (copy);
|
||||
|
||||
// Copy the other node's state and bounding volume.
|
||||
// Copy the other node's state.
|
||||
CDReader copy_cdata(copy._cycler);
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_state = copy_cdata->_state;
|
||||
cdata->_transform = copy_cdata->_transform;
|
||||
cdata->_node_bounds = copy_cdata->_node_bounds;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -487,6 +484,102 @@ is_geom_node() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::propagate_stale_bound
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called by BoundedObject::mark_bound_stale(), this
|
||||
// should make sure that all bounding volumes that
|
||||
// depend on this one are marked stale also.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PandaNode::
|
||||
propagate_stale_bound() {
|
||||
// Mark all of our parent nodes stale as well.
|
||||
CDWriter cdata(_cycler);
|
||||
Up::const_iterator ui;
|
||||
for (ui = cdata->_up.begin(); ui != cdata->_up.end(); ++ui) {
|
||||
PandaNode *parent = (*ui).get_parent();
|
||||
parent->mark_bound_stale();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::recompute_bound
|
||||
// Access: Protected, Virtual
|
||||
// Description: Recomputes the dynamic bounding volume for this
|
||||
// object. The default behavior is the compute an empty
|
||||
// bounding volume; this may be overridden to extend it
|
||||
// to create a nonempty bounding volume. However, after
|
||||
// calling this function, it is guaranteed that the
|
||||
// _bound pointer will not be shared with any other
|
||||
// stage of the pipeline, and this new pointer is
|
||||
// returned.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
BoundingVolume *PandaNode::
|
||||
recompute_bound() {
|
||||
// First, get ourselves a fresh, empty bounding volume.
|
||||
BoundingVolume *bound = BoundedObject::recompute_bound();
|
||||
nassertr(bound != (BoundingVolume*)NULL, bound);
|
||||
|
||||
// Now actually compute the bounding volume by putting it around all
|
||||
// of our child bounding volumes.
|
||||
|
||||
pvector<const BoundingVolume *> child_volumes;
|
||||
|
||||
// It goes around this node's internal bounding volume . . .
|
||||
child_volumes.push_back(&get_internal_bound());
|
||||
|
||||
CDReader cdata(_cycler);
|
||||
Down::const_iterator di;
|
||||
for (di = cdata->_down.begin(); di != cdata->_down.end(); ++di) {
|
||||
// . . . plus each node's external bounding volume.
|
||||
PandaNode *child = (*di).get_child();
|
||||
const BoundingVolume &child_bound = child->get_bound();
|
||||
child_volumes.push_back(&child_bound);
|
||||
}
|
||||
|
||||
const BoundingVolume **child_begin = &child_volumes[0];
|
||||
const BoundingVolume **child_end = child_begin + child_volumes.size();
|
||||
|
||||
bool success =
|
||||
bound->around(child_begin, child_end);
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (!success) {
|
||||
pgraph_cat.error()
|
||||
<< "Unable to recompute bounding volume for " << *this << ":\n"
|
||||
<< "Cannot put " << bound->get_type() << " around:\n";
|
||||
for (int i = 0; i < (int)child_volumes.size(); i++) {
|
||||
pgraph_cat.error(false)
|
||||
<< " " << *child_volumes[i] << "\n";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Now, if we have a transform, apply it to the bounding volume we
|
||||
// just computed.
|
||||
const TransformState *transform = get_transform();
|
||||
if (!transform->is_identity()) {
|
||||
GeometricBoundingVolume *gbv;
|
||||
DCAST_INTO_R(gbv, bound, bound);
|
||||
gbv->xform(transform->get_mat());
|
||||
}
|
||||
|
||||
return bound;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::recompute_internal_bound
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called when needed to recompute the node's
|
||||
// _internal_bound object. Nodes that contain anything
|
||||
// of substance should redefine this to do the right
|
||||
// thing.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
BoundingVolume *PandaNode::
|
||||
recompute_internal_bound() {
|
||||
return _internal_bound.recompute_bound();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::attach
|
||||
// Access: Private, Static
|
||||
|
@ -46,6 +46,7 @@ class NodeChainComponent;
|
||||
// serves as a generic node with no special properties.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA PandaNode : public TypedWritable, public Namable,
|
||||
public BoundedObject,
|
||||
virtual public ReferenceCount {
|
||||
PUBLISHED:
|
||||
PandaNode(const string &name);
|
||||
@ -106,9 +107,40 @@ PUBLISHED:
|
||||
INLINE void ls() const;
|
||||
INLINE void ls(ostream &out, int indent_level = 0) const;
|
||||
|
||||
// A node has two bounding volumes: the BoundedObject it inherits
|
||||
// from is the "external" bound and represnts the node and all of
|
||||
// its children, while the _internal_bound object is the "internal"
|
||||
// bounds and represents only the node itself.
|
||||
|
||||
// We remap the inherited set_bound() and get_bound() functions so
|
||||
// that set_bound() to a type sets the type of the external bound,
|
||||
// while set_bound() to a specific bounding volume sets the volume
|
||||
// of the *internal* bound. At the same time, get_bound() returns
|
||||
// the external bound. Although it might seem strange and confusing
|
||||
// to do this, this is actually the natural way the user thinks
|
||||
// about nodes and bounding volumes.
|
||||
INLINE void set_bound(BoundingVolumeType type);
|
||||
INLINE void set_bound(const BoundingVolume &volume);
|
||||
INLINE const BoundingVolume &get_bound() const;
|
||||
INLINE const BoundingVolume &get_internal_bound() const;
|
||||
|
||||
public:
|
||||
virtual bool is_geom_node() const;
|
||||
|
||||
protected:
|
||||
// Inherited from BoundedObject
|
||||
virtual void propagate_stale_bound();
|
||||
virtual BoundingVolume *recompute_bound();
|
||||
|
||||
// Local to PandaNode
|
||||
virtual BoundingVolume *recompute_internal_bound();
|
||||
INLINE void changed_internal_bound();
|
||||
|
||||
// This is the bounding volume around the contents of the node
|
||||
// itself (without including all of the node's children).
|
||||
// BoundedObject is itself cycled, so we don't need to protect it.
|
||||
BoundedObject _internal_bound;
|
||||
|
||||
private:
|
||||
// parent-child manipulation for NodeChain support. Don't try to
|
||||
// call these directly.
|
||||
@ -173,8 +205,6 @@ private:
|
||||
Up _up;
|
||||
Chains _chains;
|
||||
|
||||
BoundedObject _node_bounds;
|
||||
BoundedObject _subgraph_bounds;
|
||||
CPT(RenderState) _state;
|
||||
CPT(TransformState) _transform;
|
||||
};
|
||||
@ -216,9 +246,11 @@ public:
|
||||
}
|
||||
static void init_type() {
|
||||
TypedWritable::init_type();
|
||||
BoundedObject::init_type();
|
||||
ReferenceCount::init_type();
|
||||
register_type(_type_handle, "PandaNode",
|
||||
TypedWritable::get_class_type(),
|
||||
BoundedObject::get_class_type(),
|
||||
ReferenceCount::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
|
@ -160,6 +160,38 @@ is_geom_node() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomNode::recompute_internal_bound
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called when needed to recompute the node's
|
||||
// _internal_bound object. Nodes that contain anything
|
||||
// of substance should redefine this to do the right
|
||||
// thing.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
BoundingVolume *qpGeomNode::
|
||||
recompute_internal_bound() {
|
||||
// First, get ourselves a fresh, empty bounding volume.
|
||||
BoundingVolume *bound = PandaNode::recompute_internal_bound();
|
||||
nassertr(bound != (BoundingVolume *)NULL, bound);
|
||||
|
||||
// Now actually compute the bounding volume by putting it around all
|
||||
// of our geoms' bounding volumes.
|
||||
pvector<const BoundingVolume *> child_volumes;
|
||||
|
||||
CDReader cdata(_cycler);
|
||||
Geoms::const_iterator gi;
|
||||
for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) {
|
||||
const GeomEntry &entry = (*gi);
|
||||
child_volumes.push_back(&entry._geom->get_bound());
|
||||
}
|
||||
|
||||
const BoundingVolume **child_begin = &child_volumes[0];
|
||||
const BoundingVolume **child_end = child_begin + child_volumes.size();
|
||||
|
||||
bound->around(child_begin, child_end);
|
||||
return bound;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomNode::register_with_read_factory
|
||||
// Access: Public, Static
|
||||
|
@ -62,6 +62,9 @@ public:
|
||||
|
||||
virtual bool is_geom_node() const;
|
||||
|
||||
protected:
|
||||
virtual BoundingVolume *recompute_internal_bound();
|
||||
|
||||
private:
|
||||
class GeomEntry {
|
||||
public:
|
||||
|
Loading…
x
Reference in New Issue
Block a user