I think the most important factors for answering your question are missing: (a) What language you're using, and (b) What graphics library you're using. But let's see what we can do because it *is* a little confusing at first and
the wiki isn't terribly helpful here today. I am using C++ and Ogre3d 2.1 graphics.
The first thing to note is that btIDebugDraw isn't magic. It won't just draw the shapes for you *somehow* (dumb, but this was my first impression for some reason).
You need to make a class that derives from btIDebugDraw. Bullet will store your debug drawer object like this: btDynamicsWorld::setDebugDrawer( my_custom_dbg_drawer ). Then, after btDynamicsWorld::stepSimulation(), call btDynamicsWorld::debugDrawWorld(). During that function, Bullet will call btIDebugDraw::drawLine(), btIDebugDraw::drawTriangle(), btIDebugDraw::drawContactPoint(), btIDebugDraw::draw3dText(), etc on your DebugDrawer, filling my_custom_dbg_drawer with all of the information you need to build the visuals. I then use an Ogre3d FrameListener to draw the debug shapes every frame, based on the info I got from the btIDebugDraw::drawWhatever() calls. Mine is a Singleton class; here's how I set it up:
Code: Select all
DebugDrawer dbg_drawer = &DebugDrawer::getSingleton(); // DebugDrawer derives btIDebugDraw, see below for my definition
dbg_drawer->init();
dbg_drawer->setDebugMode( btIDebugDraw::DBG_DrawWireframe + btIDebugDraw::DBG_DrawContactPoints + btIDebugDraw::DBG_DrawConstraints + btIDebugDraw::DBG_DrawConstraintLimits );
dbg_drawer->debugPhysics( false );
bt_app.getWorld()->setDebugDrawer( dbg_drawer );
show_debug_drawer = true;
DebugDrawer::getSingleton().debugPhysics( show_debug_drawer );
I have copy-pasted my DebugDrawer mostly from
Ogre3d Forums Thread: [2.1] btOgre. Note that it also derives from Ogre::FrameListener, which allows Ogre to call DebugDrawer::frameStarted() and DebugDrawer::frameEnded() during each frame, and that's where I do my actual drawing. Each graphics library will have its own way of calling frames and drawing polygons. I want to say that BulletPhysics ships with an OpenGL btIDebugDraw implementation, but I couldn't quickly find it. Try
Thread: btIDebugDraw with OpenGL 4.4 - [SOLVED].
Code: Select all
class DebugDrawer: public btIDebugDraw, public Ogre::FrameListener{
public:
static DebugDrawer &getSingleton(){
static DebugDrawer instance;
return instance;
}
void init(){
sceneManager = Ogre::Root::getSingletonPtr()->getSceneManager( "SceneManager" ); // Dangerous! Shouldn't this grab <the first scenemanager>?
isDebuggingPhysics = false;
Ogre::HlmsManager *hlms_man = Ogre::Root::getSingletonPtr()->getHlmsManager();
Ogre::HlmsUnlit *unlit_hlms = static_cast<Ogre::HlmsUnlit*>(hlms_man->getHlms( Ogre::HLMS_UNLIT ));
Ogre::String datablockName = "DebugLineMat";
Ogre::HlmsUnlitDatablock *datablock = static_cast<Ogre::HlmsUnlitDatablock*>(unlit_hlms->createDatablock( datablockName,
datablockName,
Ogre::HlmsMacroblock(),
Ogre::HlmsBlendblock(),
Ogre::HlmsParamVec() ));
vertexCount = 1000000;
Ogre::Root *root = Ogre::Root::getSingletonPtr();
Ogre::RenderSystem *renderSystem = root->getRenderSystem();
Ogre::VaoManager *vaoManager = renderSystem->getVaoManager();
Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createManual( "PhysicsDebuggingMesh", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME );
Ogre::SubMesh *subMesh = mesh->createSubMesh();
Ogre::VertexElement2Vec vertexElements;
vertexElements.push_back( Ogre::VertexElement2( Ogre::VET_FLOAT3, Ogre::VES_POSITION ) );
vertexElements.push_back( Ogre::VertexElement2( Ogre::VET_FLOAT3, Ogre::VES_DIFFUSE ) );
size_t vertexSize = vaoManager->calculateVertexSize( vertexElements );
Ogre::Real* vertexData = static_cast<Ogre::Real*>(OGRE_MALLOC_SIMD( vertexSize * vertexCount, Ogre::MEMCATEGORY_GEOMETRY ));
Ogre::VertexBufferPackedVec vertexBuffers;
pVertexBuffer = vaoManager->createVertexBuffer( vertexElements, vertexCount, Ogre::BT_DYNAMIC_PERSISTENT, vertexData, false );
vertexBuffers.push_back( pVertexBuffer );
Ogre::VertexArrayObject *vao = vaoManager->createVertexArrayObject( vertexBuffers, 0, Ogre::v1::RenderOperation::OT_LINE_LIST );
subMesh->mVao[0].push_back( vao );
subMesh->mVao[1].push_back( vao );
mesh->_setBounds( Ogre::Aabb::BOX_INFINITE );
item = sceneManager->createItem( mesh, Ogre::SCENE_DYNAMIC );
item->setDatablock( datablock );
item->setCastShadows( false );
Ogre::SceneNode *sceneNode = sceneManager->getRootSceneNode( Ogre::SCENE_DYNAMIC )->createChildSceneNode( Ogre::SCENE_DYNAMIC );
sceneNode->attachObject( item );
debugModes = (DebugDrawModes)DBG_DrawWireframe;
}
void deinit(){
if( isDebuggingPhysics ) debugPhysics( false );
}
void debugPhysics( bool enable ){
isDebuggingPhysics = enable;
if( isDebuggingPhysics ){
item->setVisible( true );
Ogre::Root::getSingleton().addFrameListener( this );
}
else{
item->setVisible( false );
Ogre::Root::getSingleton().removeFrameListener( this );
}
}
virtual void drawLine( const btVector3 &from, const btVector3 &to, const btVector3 &color ){
if( !isDebuggingPhysics ) return;
if( pVertexBuffer->isCurrentlyMapped() ){
meshVertices[vertIndex++] = from.x();
meshVertices[vertIndex++] = from.y();
meshVertices[vertIndex++] = from.z();
meshVertices[vertIndex++] = color.getX();
meshVertices[vertIndex++] = color.getY();
meshVertices[vertIndex++] = color.getZ();
meshVertices[vertIndex++] = to.x();
meshVertices[vertIndex++] = to.y();
meshVertices[vertIndex++] = to.z();
meshVertices[vertIndex++] = color.getX();
meshVertices[vertIndex++] = color.getY();
meshVertices[vertIndex++] = color.getZ();
}
}
virtual void drawTriangle( const btVector3 &v0, const btVector3 &v1, const btVector3 &v2, const btVector3 &color, btScalar ){ (void)v0; (void)v1; (void)v2; (void)color; }
virtual void drawContactPoint( const btVector3 &PointOnB, const btVector3 &normalOnB, btScalar distance, int lifeTime, const btVector3 &color ){ (void)PointOnB; (void)normalOnB; (void)distance; (void)lifeTime; (void)color; }
virtual void reportErrorWarning( const char *warningString ){ (void)warningString; }
virtual void draw3dText( const btVector3 &location, const char *textString ){ (void)location; (void)textString; }
virtual void setDebugMode( int debugMode ){ debugModes = (DebugDrawModes)debugMode; }
virtual int getDebugMode() const{ return debugModes; }
protected:
bool frameStarted( const Ogre::FrameEvent& evt ){
vertIndex = 0;
meshVertices = reinterpret_cast<Ogre::Real*>(pVertexBuffer->map( 0, pVertexBuffer->getNumElements() ));
return true;
}
bool frameEnded( const Ogre::FrameEvent& evt ){
if( pVertexBuffer->isCurrentlyMapped() ) pVertexBuffer->unmap( Ogre::UO_KEEP_PERSISTENT );
return true;
}
private:
DebugDrawer(){}
//DebugDrawer( DebugDrawer const& ); //don't implement!
//void operator=( DebugDrawer const& ); //don't implement!
~DebugDrawer(){}
Ogre::SceneManager* sceneManager;
DebugDrawModes debugModes;
bool isDebuggingPhysics;
Ogre::VertexBufferPacked *pVertexBuffer;
int vertexCount;
Ogre::Item *item;
Ogre::Real* meshVertices;
int vertIndex;
};
See
Thread: Pendulums Won't Swing! for a taste of what the DebugDrawer looks like on my machine (and let me know if you can help with constraints!).