Skip to main content

History: BulletDebugDrawer

Source of version: 7 (current)

Copy to clipboard
            {maketoc}

Subclass from {MONO()}btIDebugDraw{MONO} that allows you to visualize collision shapes, contact points and more. It inherits also from {MONO()}Ogre::FrameListener{MONO} to get updates. Not all functionality is implemented yet.

See ((BulletSharpDebugDrawer)) for a C# version.

Instantiate and connect the debug drawing object like this:
{CODE(wrap="1", colors="c++")}
         mDebugDrawer = new OgreDebugDrawer( mSceneMgr );
         mDebugDrawer->setDebugMode( btIDebugDraw::DBG_DrawWireframe );
         dynamicsWorld->setDebugDrawer( mDebugDrawer );
{CODE}

When you want it to draw:
{CODE(wrap="1", colors="c++")}
dynamicsWorld->debugDrawWorld()
{CODE}

__Interpreting the debug draw output__
*If your object is drawn with a red wireframe that indicates the object is 'deactivated' and will not be subject to forces in the simulation.
*A green wireframe indicates it's active.


!!OgreBulletUtils.h
{CODE(wrap="1", colors="c++")}inline btVector3 cvt(const Ogre::Vector3 &V){
    return btVector3(V.x, V.y, V.z);
}

inline Ogre::Vector3 cvt(const btVector3&V){
    return Ogre::Vector3(V.x(), V.y(), V.z());
}

inline btQuaternion cvt(const Ogre::Quaternion &Q)
{
    return btQuaternion(Q.x, Q.y, Q.z, Q.w);
};

inline Ogre::Quaternion cvt(const btQuaternion &Q)
{
    return Ogre::Quaternion(Q.w(), Q.x(), Q.y(), Q.z());
};
{CODE}

!!DebugDrawer.h
{CODE(wrap="1", colors="c++")}#ifndef DebugDrawer_h__
#define DebugDrawer_h__

#include "../common.h"

class OgreDebugDrawer: public btIDebugDraw, public Ogre::FrameListener{
public:
    OgreDebugDrawer( Ogre::SceneManager *scm );
    ~OgreDebugDrawer ();
    virtual void     drawLine (const btVector3 &from, const btVector3 &to, const btVector3 &color);
    virtual void     drawTriangle (const btVector3 &v0, const btVector3 &v1, const btVector3 &v2, const btVector3 &color, btScalar);
    virtual void     drawContactPoint (const btVector3 &PointOnB, const btVector3 &normalOnB, btScalar distance, int lifeTime, const btVector3 &color);
    virtual void     reportErrorWarning (const char *warningString);
    virtual void     draw3dText (const btVector3 &location, const char *textString);
    virtual void     setDebugMode (int debugMode);
    virtual int     getDebugMode () const;
protected:
    bool frameStarted(const Ogre::FrameEvent& evt);
    bool frameEnded(const Ogre::FrameEvent& evt);
private:
    struct ContactPoint{
        Ogre::Vector3 from;
        Ogre::Vector3 to;
        Ogre::ColourValue   color;
        size_t        dieTime;
    };
    DebugDrawModes               mDebugModes;
    Ogre::ManualObject          *mLines;
    Ogre::ManualObject          *mTriangles;
    std::vector< ContactPoint > *mContactPoints;
    std::vector< ContactPoint >  mContactPoints1;
    std::vector< ContactPoint >  mContactPoints2;
};

#endif // DebugDrawer_h__{CODE}

!!DebugDrawer.cpp
{CODE(wrap="1", colors="c++")}#include "DebugDrawer.h"
#include "OgreBulletUtils.h"

using namespace Ogre;

OgreDebugDrawer::OgreDebugDrawer( SceneManager *scm )
{
    mContactPoints = &mContactPoints1;
    mLines = new ManualObject("physics lines");
    ASSERT( mLines );
    mTriangles = new ManualObject("physics triangles");
    ASSERT( mTriangles );
    mLines->setDynamic(true);
    mTriangles->setDynamic(true);
    //mLines->estimateVertexCount( 100000 );
    //mLines->estimateIndexCount( 0 );

    scm->getRootSceneNode()->attachObject( mLines );
    scm->getRootSceneNode()->attachObject( mTriangles );
    
    static const char * matName = "OgreBulletCollisionsDebugDefault";
    MaterialPtr mtl = MaterialManager::getSingleton().getDefaultSettings()->clone(matName);
    mtl->setReceiveShadows(false);
    mtl->setSceneBlending( SBT_TRANSPARENT_ALPHA );
    mtl->setDepthBias( 0.1, 0 );
    TextureUnitState * tu = mtl->getTechnique(0)->getPass(0)->createTextureUnitState();
    ASSERT( tu );
    tu->setColourOperationEx( LBX_SOURCE1, LBS_DIFFUSE );
    mtl->getTechnique(0)->setLightingEnabled(false);
    //mtl->getTechnique(0)->setSelfIllumination( ColourValue::White ); 

    mLines->begin( matName, RenderOperation::OT_LINE_LIST );
    mLines->position( Vector3::ZERO );
    mLines->colour( ColourValue::Blue );
    mLines->position( Vector3::ZERO );
    mLines->colour( ColourValue::Blue );

    mTriangles->begin( matName, RenderOperation::OT_TRIANGLE_LIST );
    mTriangles->position( Vector3::ZERO );
    mTriangles->colour( ColourValue::Blue );
    mTriangles->position( Vector3::ZERO );
    mTriangles->colour( ColourValue::Blue );
    mTriangles->position( Vector3::ZERO );
    mTriangles->colour( ColourValue::Blue );

    mDebugModes = (DebugDrawModes) DBG_DrawWireframe;
    Root::getSingleton().addFrameListener(this);
}

OgreDebugDrawer::~OgreDebugDrawer()
{
    Root::getSingleton().removeFrameListener(this);
    delete mLines;
    delete mTriangles;
}

void OgreDebugDrawer::drawLine( const btVector3 &from, const btVector3 &to, const btVector3 &color )
{
    ColourValue c( color.getX(), color.getY(), color.getZ() );  
    c.saturate();
    mLines->position( cvt(from) );
    mLines->colour( c );
    mLines->position( cvt(to) );
    mLines->colour( c );
}

void OgreDebugDrawer::drawTriangle( const btVector3 &v0, const btVector3 &v1, const btVector3 &v2, const btVector3 &color, btScalar alpha )
{
    ColourValue c( color.getX(), color.getY(), color.getZ(), alpha );  
    c.saturate();
    mTriangles->position( cvt(v0) );
    mTriangles->colour( c );
    mTriangles->position( cvt(v1) );
    mTriangles->colour( c );
    mTriangles->position( cvt(v2) );
    mTriangles->colour( c );
}

void OgreDebugDrawer::drawContactPoint( const btVector3 &PointOnB, const btVector3 &normalOnB, btScalar distance, int lifeTime, const btVector3 &color )
{
    mContactPoints->resize( mContactPoints->size() + 1 );
    ContactPoint p = mContactPoints->back();
    p.from = cvt( PointOnB );
    p.to = p.from + cvt( normalOnB ) * distance;
    p.dieTime = Root::getSingleton().getTimer()->getMilliseconds() + lifeTime;
    p.color.r = color.x();
    p.color.g = color.y();
    p.color.b = color.z();
}

bool OgreDebugDrawer::frameStarted( const Ogre::FrameEvent& evt )
{
    size_t now = Root::getSingleton().getTimer()->getMilliseconds();
    std::vector< ContactPoint > *newCP = mContactPoints == &mContactPoints1 ? &mContactPoints2 : &mContactPoints1;
    for ( std::vector< ContactPoint >::iterator i = mContactPoints->begin(); i < mContactPoints->end(); i++ ){
        ContactPoint &cp = *i;
        mLines->position( cp.from );
        mLines->colour( cp.color );
        mLines->position( cp.to );
        if ( now <= cp.dieTime  )
            newCP->push_back( cp );
    }
    mContactPoints->clear();
    mContactPoints = newCP;

    mLines->end();
    mTriangles->end();

    return true;
}

bool OgreDebugDrawer::frameEnded( const Ogre::FrameEvent& evt )
{
    mLines->beginUpdate(0);
    mTriangles->beginUpdate(0);
    return true;
}

void OgreDebugDrawer::reportErrorWarning( const char *warningString )
{
    LogManager::getSingleton().getDefaultLog()->logMessage( warningString );
}

void OgreDebugDrawer::draw3dText( const btVector3 &location, const char *textString )
{

}

void OgreDebugDrawer::setDebugMode( int debugMode )
{
    mDebugModes = (DebugDrawModes) debugMode;
}

int OgreDebugDrawer::getDebugMode() const
{
    return mDebugModes;
}{CODE}