mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -04:00
bullet: implement debug draw via cull callback for efficiency
Now the debug drawing will no longer happen if the debug node is not being visited by the cull pass, ie. in another scene graph. Furthermore, the generation code has been optimized a bit more. This change means it no longer inherits from GeomNode. Future improvements could include better culling (which is currently disabled entirely). Closes: #130
This commit is contained in:
parent
490dbe7b2a
commit
075cb14cbb
@ -13,20 +13,25 @@
|
|||||||
|
|
||||||
#include "bulletDebugNode.h"
|
#include "bulletDebugNode.h"
|
||||||
|
|
||||||
|
#include "cullHandler.h"
|
||||||
|
#include "cullTraverser.h"
|
||||||
|
#include "cullableObject.h"
|
||||||
#include "geomLines.h"
|
#include "geomLines.h"
|
||||||
#include "geomVertexData.h"
|
#include "geomVertexData.h"
|
||||||
#include "geomTriangles.h"
|
#include "geomTriangles.h"
|
||||||
#include "geomVertexFormat.h"
|
#include "geomVertexFormat.h"
|
||||||
#include "geomVertexWriter.h"
|
#include "geomVertexWriter.h"
|
||||||
#include "omniBoundingVolume.h"
|
#include "omniBoundingVolume.h"
|
||||||
|
#include "pStatTimer.h"
|
||||||
|
|
||||||
TypeHandle BulletDebugNode::_type_handle;
|
TypeHandle BulletDebugNode::_type_handle;
|
||||||
|
PStatCollector BulletDebugNode::_pstat_debug("App:Bullet:DoPhysics:Debug");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
BulletDebugNode::
|
BulletDebugNode::
|
||||||
BulletDebugNode(const char *name) : GeomNode(name) {
|
BulletDebugNode(const char *name) : PandaNode(name), _debug_stale(true) {
|
||||||
|
|
||||||
_wireframe = true;
|
_wireframe = true;
|
||||||
_constraints = true;
|
_constraints = true;
|
||||||
@ -37,40 +42,6 @@ BulletDebugNode(const char *name) : GeomNode(name) {
|
|||||||
set_bounds(bounds);
|
set_bounds(bounds);
|
||||||
set_final(true);
|
set_final(true);
|
||||||
set_overall_hidden(true);
|
set_overall_hidden(true);
|
||||||
|
|
||||||
// Lines
|
|
||||||
{
|
|
||||||
PT(GeomVertexData) vdata;
|
|
||||||
PT(Geom) geom;
|
|
||||||
PT(GeomLines) prim;
|
|
||||||
|
|
||||||
vdata = new GeomVertexData("", GeomVertexFormat::get_v3c4(), Geom::UH_stream);
|
|
||||||
|
|
||||||
prim = new GeomLines(Geom::UH_stream);
|
|
||||||
prim->set_shade_model(Geom::SM_uniform);
|
|
||||||
|
|
||||||
geom = new Geom(vdata);
|
|
||||||
geom->add_primitive(prim);
|
|
||||||
|
|
||||||
add_geom(geom);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Triangles
|
|
||||||
{
|
|
||||||
PT(GeomVertexData) vdata;
|
|
||||||
PT(Geom) geom;
|
|
||||||
PT(GeomTriangles) prim;
|
|
||||||
|
|
||||||
vdata = new GeomVertexData("", GeomVertexFormat::get_v3c4(), Geom::UH_stream);
|
|
||||||
|
|
||||||
prim = new GeomTriangles(Geom::UH_stream);
|
|
||||||
prim->set_shade_model(Geom::SM_uniform);
|
|
||||||
|
|
||||||
geom = new Geom(vdata);
|
|
||||||
geom->add_primitive(prim);
|
|
||||||
|
|
||||||
add_geom(geom);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -175,100 +146,133 @@ draw_mask_changed() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Returns true if there is some value to visiting this particular node during
|
||||||
|
* the cull traversal for any camera, false otherwise. This will be used to
|
||||||
|
* optimize the result of get_net_draw_show_mask(), so that any subtrees that
|
||||||
|
* contain only nodes for which is_renderable() is false need not be visited.
|
||||||
|
*/
|
||||||
|
bool BulletDebugNode::
|
||||||
|
is_renderable() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the node's contents to the CullResult we are building up during the
|
||||||
|
* cull traversal, so that it will be drawn at render time. For most nodes
|
||||||
|
* other than GeomNodes, this is a do-nothing operation.
|
||||||
*/
|
*/
|
||||||
void BulletDebugNode::
|
void BulletDebugNode::
|
||||||
sync_b2p(btDynamicsWorld *world) {
|
add_for_draw(CullTraverser *trav, CullTraverserData &data) {
|
||||||
|
PT(Geom) debug_lines;
|
||||||
|
PT(Geom) debug_triangles;
|
||||||
|
|
||||||
if (is_overall_hidden()) return;
|
{
|
||||||
|
LightMutexHolder holder(_lock);
|
||||||
nassertv(get_num_geoms() == 2);
|
if (_debug_world == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_debug_stale) {
|
||||||
|
nassertv(_debug_world != nullptr);
|
||||||
|
PStatTimer timer(_pstat_debug);
|
||||||
|
|
||||||
// Collect debug geometry data
|
// Collect debug geometry data
|
||||||
_drawer._lines.clear();
|
_drawer._lines.clear();
|
||||||
_drawer._triangles.clear();
|
_drawer._triangles.clear();
|
||||||
|
|
||||||
world->debugDrawWorld();
|
_debug_world->debugDrawWorld();
|
||||||
|
|
||||||
// Get inverse of this node's net transform
|
|
||||||
NodePath np = NodePath::any_path((PandaNode *)this);
|
|
||||||
LMatrix4 m = np.get_net_transform()->get_mat();
|
|
||||||
m.invert_in_place();
|
|
||||||
|
|
||||||
// Render lines
|
// Render lines
|
||||||
{
|
{
|
||||||
PT(GeomVertexData) vdata;
|
PT(GeomVertexData) vdata =
|
||||||
PT(Geom) geom;
|
new GeomVertexData("", GeomVertexFormat::get_v3c4(), Geom::UH_stream);
|
||||||
PT(GeomLines) prim;
|
vdata->unclean_set_num_rows(_drawer._lines.size() * 2);
|
||||||
|
|
||||||
vdata = new GeomVertexData("", GeomVertexFormat::get_v3c4(), Geom::UH_stream);
|
GeomVertexWriter vwriter(vdata, InternalName::get_vertex());
|
||||||
|
GeomVertexWriter cwriter(vdata, InternalName::get_color());
|
||||||
prim = new GeomLines(Geom::UH_stream);
|
|
||||||
prim->set_shade_model(Geom::SM_uniform);
|
|
||||||
|
|
||||||
GeomVertexWriter vwriter = GeomVertexWriter(vdata, InternalName::get_vertex());
|
|
||||||
GeomVertexWriter cwriter = GeomVertexWriter(vdata, InternalName::get_color());
|
|
||||||
|
|
||||||
int v = 0;
|
|
||||||
|
|
||||||
pvector<Line>::const_iterator lit;
|
pvector<Line>::const_iterator lit;
|
||||||
for (lit = _drawer._lines.begin(); lit != _drawer._lines.end(); lit++) {
|
for (lit = _drawer._lines.begin(); lit != _drawer._lines.end(); lit++) {
|
||||||
Line line = *lit;
|
const Line &line = *lit;
|
||||||
|
|
||||||
vwriter.add_data3(m.xform_point(line._p0));
|
vwriter.set_data3(line._p0);
|
||||||
vwriter.add_data3(m.xform_point(line._p1));
|
vwriter.set_data3(line._p1);
|
||||||
cwriter.add_data4(LVecBase4(line._color));
|
cwriter.set_data4(LVecBase4(line._color));
|
||||||
cwriter.add_data4(LVecBase4(line._color));
|
cwriter.set_data4(LVecBase4(line._color));
|
||||||
|
|
||||||
prim->add_vertex(v++);
|
|
||||||
prim->add_vertex(v++);
|
|
||||||
prim->close_primitive();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
geom = new Geom(vdata);
|
PT(GeomPrimitive) prim = new GeomLines(Geom::UH_stream);
|
||||||
geom->add_primitive(prim);
|
prim->set_shade_model(Geom::SM_uniform);
|
||||||
|
prim->add_next_vertices(_drawer._lines.size() * 2);
|
||||||
|
|
||||||
set_geom(0, geom);
|
debug_lines = new Geom(vdata);
|
||||||
|
debug_lines->add_primitive(prim);
|
||||||
|
_debug_lines = debug_lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render triangles
|
// Render triangles
|
||||||
{
|
{
|
||||||
PT(GeomVertexData) vdata;
|
PT(GeomVertexData) vdata =
|
||||||
PT(Geom) geom;
|
new GeomVertexData("", GeomVertexFormat::get_v3c4(), Geom::UH_stream);
|
||||||
PT(GeomTriangles) prim;
|
vdata->unclean_set_num_rows(_drawer._triangles.size() * 3);
|
||||||
|
|
||||||
vdata = new GeomVertexData("", GeomVertexFormat::get_v3c4(), Geom::UH_stream);
|
GeomVertexWriter vwriter(vdata, InternalName::get_vertex());
|
||||||
|
GeomVertexWriter cwriter(vdata, InternalName::get_color());
|
||||||
prim = new GeomTriangles(Geom::UH_stream);
|
|
||||||
prim->set_shade_model(Geom::SM_uniform);
|
|
||||||
|
|
||||||
GeomVertexWriter vwriter = GeomVertexWriter(vdata, InternalName::get_vertex());
|
|
||||||
GeomVertexWriter cwriter = GeomVertexWriter(vdata, InternalName::get_color());
|
|
||||||
|
|
||||||
int v = 0;
|
|
||||||
|
|
||||||
pvector<Triangle>::const_iterator tit;
|
pvector<Triangle>::const_iterator tit;
|
||||||
for (tit = _drawer._triangles.begin(); tit != _drawer._triangles.end(); tit++) {
|
for (tit = _drawer._triangles.begin(); tit != _drawer._triangles.end(); tit++) {
|
||||||
Triangle tri = *tit;
|
const Triangle &tri = *tit;
|
||||||
|
|
||||||
vwriter.add_data3(m.xform_point(tri._p0));
|
vwriter.set_data3(tri._p0);
|
||||||
vwriter.add_data3(m.xform_point(tri._p1));
|
vwriter.set_data3(tri._p1);
|
||||||
vwriter.add_data3(m.xform_point(tri._p2));
|
vwriter.set_data3(tri._p2);
|
||||||
cwriter.add_data4(LVecBase4(tri._color));
|
cwriter.set_data4(LVecBase4(tri._color));
|
||||||
cwriter.add_data4(LVecBase4(tri._color));
|
cwriter.set_data4(LVecBase4(tri._color));
|
||||||
cwriter.add_data4(LVecBase4(tri._color));
|
cwriter.set_data4(LVecBase4(tri._color));
|
||||||
|
|
||||||
prim->add_vertex(v++);
|
|
||||||
prim->add_vertex(v++);
|
|
||||||
prim->add_vertex(v++);
|
|
||||||
prim->close_primitive();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
geom = new Geom(vdata);
|
PT(GeomPrimitive) prim = new GeomTriangles(Geom::UH_stream);
|
||||||
geom->add_primitive(prim);
|
prim->set_shade_model(Geom::SM_uniform);
|
||||||
|
prim->add_next_vertices(_drawer._triangles.size() * 3);
|
||||||
|
|
||||||
set_geom(1, geom);
|
debug_triangles = new Geom(vdata);
|
||||||
|
debug_triangles->add_primitive(prim);
|
||||||
|
_debug_triangles = debug_triangles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear collected data.
|
||||||
|
_drawer._lines.clear();
|
||||||
|
_drawer._triangles.clear();
|
||||||
|
|
||||||
|
_debug_stale = false;
|
||||||
|
} else {
|
||||||
|
debug_lines = _debug_lines;
|
||||||
|
debug_triangles = _debug_triangles;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record them without any state or transform.
|
||||||
|
trav->_geoms_pcollector.add_level(2);
|
||||||
|
{
|
||||||
|
CullableObject *object =
|
||||||
|
new CullableObject(move(debug_lines), RenderState::make_empty(), trav->get_scene()->get_cs_world_transform());
|
||||||
|
trav->get_cull_handler()->record_object(object, trav);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
CullableObject *object =
|
||||||
|
new CullableObject(move(debug_triangles), RenderState::make_empty(), trav->get_scene()->get_cs_world_transform());
|
||||||
|
trav->get_cull_handler()->record_object(object, trav);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void BulletDebugNode::
|
||||||
|
sync_b2p(btDynamicsWorld *world) {
|
||||||
|
LightMutexHolder holder(_lock);
|
||||||
|
|
||||||
|
_debug_world = world;
|
||||||
|
_debug_stale = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -431,8 +435,6 @@ register_with_read_factory() {
|
|||||||
*/
|
*/
|
||||||
void BulletDebugNode::
|
void BulletDebugNode::
|
||||||
write_datagram(BamWriter *manager, Datagram &dg) {
|
write_datagram(BamWriter *manager, Datagram &dg) {
|
||||||
// Don't upcall to GeomNode since we're not interested in storing the actual
|
|
||||||
// debug Geoms in the .bam file.
|
|
||||||
PandaNode::write_datagram(manager, dg);
|
PandaNode::write_datagram(manager, dg);
|
||||||
|
|
||||||
dg.add_bool(_wireframe);
|
dg.add_bool(_wireframe);
|
||||||
@ -464,8 +466,6 @@ make_from_bam(const FactoryParams ¶ms) {
|
|||||||
*/
|
*/
|
||||||
void BulletDebugNode::
|
void BulletDebugNode::
|
||||||
fillin(DatagramIterator &scan, BamReader *manager) {
|
fillin(DatagramIterator &scan, BamReader *manager) {
|
||||||
// Don't upcall to GeomNode since we're not interested in storing the actual
|
|
||||||
// debug Geoms in the .bam file.
|
|
||||||
PandaNode::fillin(scan, manager);
|
PandaNode::fillin(scan, manager);
|
||||||
|
|
||||||
_wireframe = scan.get_bool();
|
_wireframe = scan.get_bool();
|
||||||
|
@ -17,13 +17,12 @@
|
|||||||
#include "pandabase.h"
|
#include "pandabase.h"
|
||||||
|
|
||||||
#include "bullet_includes.h"
|
#include "bullet_includes.h"
|
||||||
|
#include "lightMutex.h"
|
||||||
#include "geomNode.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class EXPCL_PANDABULLET BulletDebugNode : public GeomNode {
|
class EXPCL_PANDABULLET BulletDebugNode : public PandaNode {
|
||||||
|
|
||||||
PUBLISHED:
|
PUBLISHED:
|
||||||
BulletDebugNode(const char *name="debug");
|
BulletDebugNode(const char *name="debug");
|
||||||
@ -53,6 +52,9 @@ public:
|
|||||||
virtual bool safe_to_combine_children() const;
|
virtual bool safe_to_combine_children() const;
|
||||||
virtual bool safe_to_flatten_below() const;
|
virtual bool safe_to_flatten_below() const;
|
||||||
|
|
||||||
|
virtual bool is_renderable() const;
|
||||||
|
virtual void add_for_draw(CullTraverser *trav, CullTraverserData &data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void sync_b2p(btDynamicsWorld *world);
|
void sync_b2p(btDynamicsWorld *world);
|
||||||
|
|
||||||
@ -100,14 +102,22 @@ private:
|
|||||||
int _mode;
|
int _mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
LightMutex _lock;
|
||||||
DebugDraw _drawer;
|
DebugDraw _drawer;
|
||||||
|
|
||||||
|
bool _debug_stale;
|
||||||
|
btDynamicsWorld *_debug_world;
|
||||||
|
PT(Geom) _debug_lines;
|
||||||
|
PT(Geom) _debug_triangles;
|
||||||
|
|
||||||
bool _wireframe;
|
bool _wireframe;
|
||||||
bool _constraints;
|
bool _constraints;
|
||||||
bool _bounds;
|
bool _bounds;
|
||||||
|
|
||||||
friend class BulletWorld;
|
friend class BulletWorld;
|
||||||
|
|
||||||
|
static PStatCollector _pstat_debug;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void register_with_read_factory();
|
static void register_with_read_factory();
|
||||||
virtual void write_datagram(BamWriter *manager, Datagram &dg);
|
virtual void write_datagram(BamWriter *manager, Datagram &dg);
|
||||||
@ -121,9 +131,9 @@ public:
|
|||||||
return _type_handle;
|
return _type_handle;
|
||||||
}
|
}
|
||||||
static void init_type() {
|
static void init_type() {
|
||||||
GeomNode::init_type();
|
PandaNode::init_type();
|
||||||
register_type(_type_handle, "BulletDebugNode",
|
register_type(_type_handle, "BulletDebugNode",
|
||||||
GeomNode::get_class_type());
|
PandaNode::get_class_type());
|
||||||
}
|
}
|
||||||
virtual TypeHandle get_type() const {
|
virtual TypeHandle get_type() const {
|
||||||
return get_class_type();
|
return get_class_type();
|
||||||
|
@ -55,21 +55,12 @@ INLINE BulletWorld::
|
|||||||
*/
|
*/
|
||||||
INLINE void BulletWorld::
|
INLINE void BulletWorld::
|
||||||
set_debug_node(BulletDebugNode *node) {
|
set_debug_node(BulletDebugNode *node) {
|
||||||
|
|
||||||
nassertv(node);
|
nassertv(node);
|
||||||
|
if (node != _debug) {
|
||||||
|
clear_debug_node();
|
||||||
_debug = node;
|
_debug = node;
|
||||||
_world->setDebugDrawer(&(_debug->_drawer));
|
_world->setDebugDrawer(&(_debug->_drawer));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
INLINE void BulletWorld::
|
|
||||||
clear_debug_node() {
|
|
||||||
|
|
||||||
_debug = NULL;
|
|
||||||
_world->setDebugDrawer(NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "bulletSoftBodyWorldInfo.h"
|
#include "bulletSoftBodyWorldInfo.h"
|
||||||
|
|
||||||
#include "collideMask.h"
|
#include "collideMask.h"
|
||||||
|
#include "lightMutexHolder.h"
|
||||||
|
|
||||||
#define clamp(x, x_min, x_max) max(min(x, x_max), x_min)
|
#define clamp(x, x_min, x_max) max(min(x, x_max), x_min)
|
||||||
|
|
||||||
@ -24,7 +25,6 @@ TypeHandle BulletWorld::_type_handle;
|
|||||||
|
|
||||||
PStatCollector BulletWorld::_pstat_physics("App:Bullet:DoPhysics");
|
PStatCollector BulletWorld::_pstat_physics("App:Bullet:DoPhysics");
|
||||||
PStatCollector BulletWorld::_pstat_simulation("App:Bullet:DoPhysics:Simulation");
|
PStatCollector BulletWorld::_pstat_simulation("App:Bullet:DoPhysics:Simulation");
|
||||||
PStatCollector BulletWorld::_pstat_debug("App:Bullet:DoPhysics:Debug");
|
|
||||||
PStatCollector BulletWorld::_pstat_p2b("App:Bullet:DoPhysics:SyncP2B");
|
PStatCollector BulletWorld::_pstat_p2b("App:Bullet:DoPhysics:SyncP2B");
|
||||||
PStatCollector BulletWorld::_pstat_b2p("App:Bullet:DoPhysics:SyncB2P");
|
PStatCollector BulletWorld::_pstat_b2p("App:Bullet:DoPhysics:SyncB2P");
|
||||||
|
|
||||||
@ -127,6 +127,19 @@ get_world_info() {
|
|||||||
return BulletSoftBodyWorldInfo(_info);
|
return BulletSoftBodyWorldInfo(_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a debug node that has been assigned to this BulletWorld.
|
||||||
|
*/
|
||||||
|
void BulletWorld::
|
||||||
|
clear_debug_node() {
|
||||||
|
if (_debug != nullptr) {
|
||||||
|
LightMutexHolder holder(_debug->_lock);
|
||||||
|
_debug->_debug_world = nullptr;
|
||||||
|
_world->setDebugDrawer(nullptr);
|
||||||
|
_debug = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -184,9 +197,7 @@ do_physics(PN_stdfloat dt, int max_substeps, PN_stdfloat stepsize) {
|
|||||||
|
|
||||||
// Render debug
|
// Render debug
|
||||||
if (_debug) {
|
if (_debug) {
|
||||||
_pstat_debug.start();
|
|
||||||
_debug->sync_b2p(_world);
|
_debug->sync_b2p(_world);
|
||||||
_pstat_debug.stop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_pstat_physics.stop();
|
_pstat_physics.stop();
|
||||||
|
@ -63,7 +63,7 @@ PUBLISHED:
|
|||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
INLINE void set_debug_node(BulletDebugNode *node);
|
INLINE void set_debug_node(BulletDebugNode *node);
|
||||||
INLINE void clear_debug_node();
|
void clear_debug_node();
|
||||||
INLINE BulletDebugNode *get_debug_node() const;
|
INLINE BulletDebugNode *get_debug_node() const;
|
||||||
INLINE bool has_debug_node() const;
|
INLINE bool has_debug_node() const;
|
||||||
|
|
||||||
@ -208,7 +208,6 @@ private:
|
|||||||
|
|
||||||
static PStatCollector _pstat_physics;
|
static PStatCollector _pstat_physics;
|
||||||
static PStatCollector _pstat_simulation;
|
static PStatCollector _pstat_simulation;
|
||||||
static PStatCollector _pstat_debug;
|
|
||||||
static PStatCollector _pstat_p2b;
|
static PStatCollector _pstat_p2b;
|
||||||
static PStatCollector _pstat_b2p;
|
static PStatCollector _pstat_b2p;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user