mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 02:15:43 -04:00
pgraph bounding volumes
This commit is contained in:
parent
5a7b991858
commit
168c647d05
@ -98,6 +98,8 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
static TypeHandle _type_handle;
|
static TypeHandle _type_handle;
|
||||||
|
|
||||||
|
friend class PandaNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef DONT_INLINE_GRAPH
|
#ifndef DONT_INLINE_GRAPH
|
||||||
|
@ -19,10 +19,10 @@
|
|||||||
#ifndef BOUNDINGVOLUME_H
|
#ifndef BOUNDINGVOLUME_H
|
||||||
#define BOUNDINGVOLUME_H
|
#define BOUNDINGVOLUME_H
|
||||||
|
|
||||||
#include <pandabase.h>
|
#include "pandabase.h"
|
||||||
|
|
||||||
#include <typedObject.h>
|
#include "typedObject.h"
|
||||||
#include <typedReferenceCount.h>
|
#include "typedReferenceCount.h"
|
||||||
|
|
||||||
class BoundingSphere;
|
class BoundingSphere;
|
||||||
class BoundingHexahedron;
|
class BoundingHexahedron;
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include "cullBinBackToFront.h"
|
#include "cullBinBackToFront.h"
|
||||||
#include "graphicsStateGuardianBase.h"
|
#include "graphicsStateGuardianBase.h"
|
||||||
|
#include "geometricBoundingVolume.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
@ -33,14 +34,22 @@ TypeHandle CullBinBackToFront::_type_handle;
|
|||||||
void CullBinBackToFront::
|
void CullBinBackToFront::
|
||||||
add_geom(Geom *geom, const TransformState *transform,
|
add_geom(Geom *geom, const TransformState *transform,
|
||||||
const RenderState *state) {
|
const RenderState *state) {
|
||||||
// Since we don't have bounding volumes yet, for now we'll just use
|
// Determine the center of the bounding volume.
|
||||||
// the origin of the node. Only accurate for local transforms.
|
const BoundingVolume &volume = geom->get_bound();
|
||||||
const LMatrix4f &mat = transform->get_mat();
|
|
||||||
const LVecBase3f &pos = mat.get_row3(3);
|
|
||||||
|
|
||||||
// Oops! Don't have compute_distance_to() here either!
|
if (!volume.is_empty() &&
|
||||||
float dist = -pos[2];
|
volume.is_of_type(GeometricBoundingVolume::get_class_type())) {
|
||||||
_geoms.push_back(GeomData(geom, transform, state, dist));
|
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) {
|
set_transform(const TransformState *transform) {
|
||||||
CDWriter cdata(_cycler);
|
CDWriter cdata(_cycler);
|
||||||
cdata->_transform = transform;
|
cdata->_transform = transform;
|
||||||
|
mark_bound_stale();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -391,6 +392,71 @@ ls(ostream &out, int indent_level) const {
|
|||||||
r_list_descendants(out, indent_level);
|
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
|
// Function: PandaNode::get_children
|
||||||
// Access: Public
|
// Access: Public
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "bamReader.h"
|
#include "bamReader.h"
|
||||||
#include "bamWriter.h"
|
#include "bamWriter.h"
|
||||||
#include "indent.h"
|
#include "indent.h"
|
||||||
|
#include "geometricBoundingVolume.h"
|
||||||
|
|
||||||
|
|
||||||
TypeHandle PandaNode::_type_handle;
|
TypeHandle PandaNode::_type_handle;
|
||||||
@ -37,8 +38,6 @@ CData(const PandaNode::CData ©) :
|
|||||||
_down(copy._down),
|
_down(copy._down),
|
||||||
_up(copy._up),
|
_up(copy._up),
|
||||||
_chains(copy._chains),
|
_chains(copy._chains),
|
||||||
_node_bounds(copy._node_bounds),
|
|
||||||
_subgraph_bounds(copy._subgraph_bounds),
|
|
||||||
_state(copy._state),
|
_state(copy._state),
|
||||||
_transform(copy._transform)
|
_transform(copy._transform)
|
||||||
{
|
{
|
||||||
@ -93,12 +92,11 @@ PandaNode(const PandaNode ©) :
|
|||||||
{
|
{
|
||||||
// Copying a node does not copy its children.
|
// 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);
|
CDReader copy_cdata(copy._cycler);
|
||||||
CDWriter cdata(_cycler);
|
CDWriter cdata(_cycler);
|
||||||
cdata->_state = copy_cdata->_state;
|
cdata->_state = copy_cdata->_state;
|
||||||
cdata->_transform = copy_cdata->_transform;
|
cdata->_transform = copy_cdata->_transform;
|
||||||
cdata->_node_bounds = copy_cdata->_node_bounds;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -112,12 +110,11 @@ operator = (const PandaNode ©) {
|
|||||||
Namable::operator = (copy);
|
Namable::operator = (copy);
|
||||||
ReferenceCount::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);
|
CDReader copy_cdata(copy._cycler);
|
||||||
CDWriter cdata(_cycler);
|
CDWriter cdata(_cycler);
|
||||||
cdata->_state = copy_cdata->_state;
|
cdata->_state = copy_cdata->_state;
|
||||||
cdata->_transform = copy_cdata->_transform;
|
cdata->_transform = copy_cdata->_transform;
|
||||||
cdata->_node_bounds = copy_cdata->_node_bounds;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -487,6 +484,102 @@ is_geom_node() const {
|
|||||||
return false;
|
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
|
// Function: PandaNode::attach
|
||||||
// Access: Private, Static
|
// Access: Private, Static
|
||||||
|
@ -46,6 +46,7 @@ class NodeChainComponent;
|
|||||||
// serves as a generic node with no special properties.
|
// serves as a generic node with no special properties.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
class EXPCL_PANDA PandaNode : public TypedWritable, public Namable,
|
class EXPCL_PANDA PandaNode : public TypedWritable, public Namable,
|
||||||
|
public BoundedObject,
|
||||||
virtual public ReferenceCount {
|
virtual public ReferenceCount {
|
||||||
PUBLISHED:
|
PUBLISHED:
|
||||||
PandaNode(const string &name);
|
PandaNode(const string &name);
|
||||||
@ -106,9 +107,40 @@ PUBLISHED:
|
|||||||
INLINE void ls() const;
|
INLINE void ls() const;
|
||||||
INLINE void ls(ostream &out, int indent_level = 0) 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:
|
public:
|
||||||
virtual bool is_geom_node() const;
|
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:
|
private:
|
||||||
// parent-child manipulation for NodeChain support. Don't try to
|
// parent-child manipulation for NodeChain support. Don't try to
|
||||||
// call these directly.
|
// call these directly.
|
||||||
@ -173,8 +205,6 @@ private:
|
|||||||
Up _up;
|
Up _up;
|
||||||
Chains _chains;
|
Chains _chains;
|
||||||
|
|
||||||
BoundedObject _node_bounds;
|
|
||||||
BoundedObject _subgraph_bounds;
|
|
||||||
CPT(RenderState) _state;
|
CPT(RenderState) _state;
|
||||||
CPT(TransformState) _transform;
|
CPT(TransformState) _transform;
|
||||||
};
|
};
|
||||||
@ -216,9 +246,11 @@ public:
|
|||||||
}
|
}
|
||||||
static void init_type() {
|
static void init_type() {
|
||||||
TypedWritable::init_type();
|
TypedWritable::init_type();
|
||||||
|
BoundedObject::init_type();
|
||||||
ReferenceCount::init_type();
|
ReferenceCount::init_type();
|
||||||
register_type(_type_handle, "PandaNode",
|
register_type(_type_handle, "PandaNode",
|
||||||
TypedWritable::get_class_type(),
|
TypedWritable::get_class_type(),
|
||||||
|
BoundedObject::get_class_type(),
|
||||||
ReferenceCount::get_class_type());
|
ReferenceCount::get_class_type());
|
||||||
}
|
}
|
||||||
virtual TypeHandle get_type() const {
|
virtual TypeHandle get_type() const {
|
||||||
|
@ -160,6 +160,38 @@ is_geom_node() const {
|
|||||||
return true;
|
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
|
// Function: qpGeomNode::register_with_read_factory
|
||||||
// Access: Public, Static
|
// Access: Public, Static
|
||||||
|
@ -62,6 +62,9 @@ public:
|
|||||||
|
|
||||||
virtual bool is_geom_node() const;
|
virtual bool is_geom_node() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual BoundingVolume *recompute_internal_bound();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class GeomEntry {
|
class GeomEntry {
|
||||||
public:
|
public:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user