Collision counter in bullet physics

deepak_um
Posts: 1
Joined: Sat Apr 25, 2015 4:13 am

Collision counter in bullet physics

Post by deepak_um »

Hi ,

I am doing a project in openGL bullet physics.I am currently working on the demos of BulletPhysics which are present in gitHub.

It consists of a number of demos such as BasicDemo,ForkLIft Demo,Fracture Demo,Forklift demo,Vehicle Demo and the like.

Currently I am working on the Basic Demo application file.As I have shown in the file,the image of throwing a bullet on a right click against the objects.
image1.png
Is there some way to implement a collision counter such that when the bullet I throw collides with the objects I display a counter which gets incremented each time a collision happens.(eg:how debugDrawWorld and stepSimulation is displayed in the left corner)

I want to display Collision count the same way and increment it with each collision.

so the first time i hit it ,the counter becomes 1,the second time it becomes 2 and so on.

Any help regarding this is much appreciated.

Thanks,
Deepak.
You do not have the required permissions to view the files attached to this post.
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: Collision counter in bullet physics

Post by drleviathan »

Bullet doesn't provide a system to generate collision events between objects -- you have to write your own. If you search these forums or other pages you might find examples that people have provided. Here is a modified system that I pulled out of a project I'm working on, which itself was based on an example that someone else provided. I provide it here in case you find it useful.

Please note the following:

(1) I haven't tested this modified version of the code so maybe it has bugs! If so you'll have to find and fix yourself.

(2) It won't even compile if you don't have certain things setup already (e.g. a m_collisionDispatcher in the right context).

(3) The code prints out minimal info about each collision event. Those are the spots in the code where you would modify it to do what you specifically want.

An overview of the code is as follows: after stepSimulation() you walk all the ContactManifolds. For each pair of touching objects you update a class instance that records info about that touch (which is stored in a Map). After updating all contacts for that step you then walk all known contacts in the Map looking for those that were just added (BEGIN), those that have been touching for a while (CONTINUE) and those that are no longer touching (END) which are subsequently removed from the Map.

Put this code in a header or maybe up near the top of the correct cpp file:

Code: Select all

enum ContactEventType {
    CONTACT_EVENT_TYPE_START,  
    CONTACT_EVENT_TYPE_CONTINUE,
    CONTACT_EVENT_TYPE_END
};      

// simple map key for pair of touching objects
class ContactKey 
{
public:
    ContactKey(btCollisionObject* a, btCollisionObject* b) : m_a(a), m_b(b) {}
    bool operator<(const ContactKey& other) const { return m_a < other.m_a || (m_a == other.m_a && m_b < other.m_b); }
    bool operator==(const ContactKey& other) const { return m_a == other.m_a && m_b == other.m_b; }
    btCollisionObject* m_a;
    btCollisionObject* m_b;
};
        
// simple class for tracking contact between two objects
class ContactInfo 
{       
public: 
    void update(uint32_t currentStep, btManifoldPoint& p) 
    {
        m_lastStep = currentStep;
        ++m_numCollisions;
        // uncomment these if you care about contact details
        //m_contactPoint = p.m_positionWorldOnB;
        //m_penetration = p.m_distance1 * p.m_normalWorldOnB;
        //m_normal = p.m_normalWorldOnB;
    }   

    ContactEventType computeType(uint32_t thisStep) const
    {
        if (m_lastStep != thisStep) 
        {
            return CONTACT_EVENT_TYPE_END;
        }   
        return (m_numCollisions == 1) ? CONTACT_EVENT_TYPE_START : CONTACT_EVENT_TYPE_CONTINUE;
    }

    uint32_t m_lastStep = 0;
    uint32_t m_numCollisions = 0;
    //btVector3 m_contactPoint;
    //btVector3 m_penetration;
    //btVector3 m_normal;
};              

typedef std::map<ContactKey, ContactInfo> ContactMap; 
ContactMap m_contactMap;

uint32_t m_numContactFrames = 0;
Put this code after where you call stepSimulation() on the DynamicsWorld. As an optimization: you don't need to call this code unless stepSimulation() actually took at least one real subStep:

Code: Select all

    // walk all manifolds and add/update tracked contacts
    int numManifolds = m_collisionDispatcher->getNumManifolds();
    for (int i = 0; i < numManifolds; ++i) 
    {
        btPersistentManifold* contactManifold =  m_collisionDispatcher->getManifoldByIndexInternal(i);
        if (contactManifold->getNumContacts() > 0) 
        {
            const btCollisionObject* objectA = static_cast<const btCollisionObject*>(contactManifold->getBody0());
            const btCollisionObject* objectB = static_cast<const btCollisionObject*>(contactManifold->getBody1());

            if (!(objectA->isActive() || objectB->isActive())) 
            {
                // both objects are inactive so don't update this contact, 
                // which will trigger a CONTACT_EVENT_TYPE_END later.
                continue;
            }
            m_contactMap[ContactKey(a, b)].update(m_numContactFrames, contactManifold->getContactPoint(0));
        }
    }

    // scan known contacts and trigger events
    const uint32_t CONTINUE_EVENT_FILTER_FREQUENCY = 10;
    ContactMap::iterator contactItr = m_contactMap.begin();
    while (contactItr != m_contactMap.end()) 
    {
        btCollisionObject* A = contactItr->first.m_a;
        btCollisionObject* B = contactItr->first.m_b;
        
        ContactInfo& contact = contactItr->second;
        ContactEventType type = contact.computeType(m_numContactFrames);
        if (type == CONTACT_EVENT_TYPE_BEGIN) {
            std::cout << A << " and " << B << " START" << std::endl;
        }
        else if (type == CONTACT_EVENT_TYPE_CONTINUE) {
            // only handle CONTINUE events every so often
            if (contact.m_numCollisions % CONTINUE_EVENT_FILTER_FREQUENCY == 0) 
            {
                std::cout << A << " and " << B << " CONTINUE " << (contact.m_numCollisions / CONTINUE_EVENT_FILTER_FREQUENCY) << std::endl;
            }   
        }
        if (type == CONTACT_EVENT_TYPE_END) 
        {
            std::cout << A << " and " << B << " END";
            ContactMap::iterator iterToDelete = contactItr;
            ++contactItr;
            m_contactMap.erase(iterToDelete);
        } 
        else 
        {
            ++contactItr;
        }
    }
    ++m_numContactFrames;