Page 1 of 2

Collision callbacks questions

Posted: Tue Aug 25, 2009 11:33 pm
by garvek
Hello all,

I'm a big newbie in Bullet Physics and I'm having big troubles with the Collision thing. Sorry in advance, since it is probably something largely discussed but I didn't get a clear response from my past research.

From the docs:
Filtering collisions using masks
Bullet supports bitwise masks as a way of deciding whether or not things should collide with other
things, or receive collisions.
For example, in a spaceship game, you could have your spaceships ignore collisions with other
spaceships [the spaceships would just fly through each other], but always collide with walls [the
spaceships always bounce off walls].
Your spaceship needs a callback when it collides with a wall [for example, to produce a “plink”
sound], but the walls do nothing when you collide with them so they do not need to receive callbacks.
A third type of object, “powerup”, collides with walls and spaceships. Spaceships do not receive
collisions from them, since we don't want the trajectory of the spaceship changed by collecting a
powerup. The powerup object modifies the spaceship from its own collision callback.

The text suggest that you have a collision callback available with masks. But after a lot of search (forums, doxygen, ...) and looking at the demos I did'nt find any callback in the meaning of "have a function which is called when this object is collided". The CollisionInterface demo uses the big loop with manifolds.

The only thing I could conclude is that there's actually no callback available, except the global ones which work with all objects and at early stage.


So my question is: do we have a callback at object level, or do we definitively have to process all pairs in a loop and try to use techniques to filter as much as possible (like ghost objects) ? Knowing this would help me much, since I can focus on this, instead of trying to find out this mysterious callback thing.

Thanks !


EDIT/
After further crawling in ye-old archives, it seems that I eventually need to process the loop, it ought to be the only way ... Maybe I didn't understand the concept of bullet callback, it must mean "the object reacts" here.

Re: Misunderstanding of collision callbacks

Posted: Thu Aug 27, 2009 10:24 pm
by garvek
Hello again,

I've finally implemented the big loop to detect collision like in the demo. At the moment I don't use ghost objects but I may plan later. My question is still about a collision detect signal.

I'm using 2 std::maps in order to store new and old contacts, and I compare them to detect new ones and contacts loss. I'd like to know if it is the right way to proceed or if there's a better manner:

Code: Select all

void PhysicsManagerImpl::checkCollisions()
{
    map<btCollisionObject*, CollisionInfo> newContacts;

    /* Browse all collision pairs */
    int numManifolds = m_dynamicsWorld->getDispatcher()->getNumManifolds();
	for (int i=0; i<numManifolds; i++)
	{
		btPersistentManifold* contactManifold = m_dynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i);
		btCollisionObject* obA = static_cast<btCollisionObject*>(contactManifold->getBody0());
		btCollisionObject* obB = static_cast<btCollisionObject*>(contactManifold->getBody1());
	
        /* Check all contacts points */
		int numContacts = contactManifold->getNumContacts();
		for (int j=0;j<numContacts;j++)
		{
			btManifoldPoint& pt = contactManifold->getContactPoint(j);
			if (pt.getDistance()<0.f)
			{
                //std::cout << "Contact found" << std::endl;

				const btVector3& ptA = pt.getPositionWorldOnA();
				const btVector3& ptB = pt.getPositionWorldOnB();
				const btVector3& normalOnB = pt.m_normalWorldOnB;

                if (newContacts.find(obB) == newContacts.end())
                {
                    newContacts[obB] = CollisionInfo(obA, ptA, ptB, normalOnB);
                }
			}
		}
	}

    /* Check for added contacts ... */
    map<btCollisionObject*, CollisionInfo>::iterator it;
    if (!newContacts.empty())
    {
        for (it = newContacts.begin(); it != newContacts.end(); it++)
        {
            if (m_contacts.find((*it).first) == m_contacts.end())
            {
                std::cout << "Collision detected" << std::endl;
                // TODO: signal
            }
            else
            {
                // Remove to filter no more active contacts
                m_contacts.erase((*it).first);
            }
        }
    }

    /* ... and removed contacts */
    if (!m_contacts.empty())
    {
        for (it = m_contacts.begin(); it != m_contacts.end(); it++)
        {
            std::cout << "End of collision detected" << std::endl;
            // TODO: signal
        }
        m_contacts.clear();
    }

    m_contacts = newContacts;
}
(CollisionInfo is a simple structure to store collision characteristics).


Any comment on this would be much appreciated :)


EDIT/
Fixed some typo and changed topic title to a more appropriate one

Re: Collision callbacks questions

Posted: Thu Oct 08, 2009 9:45 am
by kidchaos2k9
Hi there,

I am also working on some kind of spaceship game and still having doubts about ghosts objects and collisions objects... However if you are still having doubts i will recommend you reading the latest version of Game Coding Complete and check the sources at http://www.mcshaffry.com/GameCode/index.php?sid=, the implementation synchronizes games objects and physics objects in the bulleTtickcallback at the end of the step simulation...

Hope this helps

Regards,

@B^)>

Re: Collision callbacks questions

Posted: Sat Oct 10, 2009 8:37 pm
by Fred_FS
I am using a very similar method to check for collisions but I get some problems with rigid bodys that are within other bodys.
So I have something like a trigger which bekongs to another object, but in this trigger is another object. But this smaller object is not registered to collide with my player.
Do you know how to solve this problem?

EDIT: This is my code, to check for collision:

Code: Select all

	std::map< btCollisionObject*, std::pair<game_object*, game_object*> > new_contacts;

	int num_manifolds = physics_world_->getDispatcher()->getNumManifolds();
	for( int i=0; i<num_manifolds; i++ )
	{
		btPersistentManifold* contact_manifold = physics_world_->getDispatcher()->getManifoldByIndexInternal(i);
		btCollisionObject* obj_a = static_cast<btCollisionObject*>( contact_manifold->getBody0() );
		btCollisionObject* obj_b = static_cast<btCollisionObject*>( contact_manifold->getBody1() );

		int num_contacts = contact_manifold->getNumContacts();
		for( int j=0; j<num_contacts; j++ )
		{
			btManifoldPoint& pt = contact_manifold->getContactPoint(j);
			if( pt.getDistance() < 0.0f )
			{
				if( new_contacts.find(obj_b) == new_contacts.end() )
				{
					if(obj_b->getUserPointer())
					{
						if( static_cast<game_object*>(obj_b->getUserPointer())->get_check_collision() )
							new_contacts[obj_b] = std::make_pair<game_object*, game_object*>( static_cast<game_object*>(obj_b->getUserPointer()), 
																							static_cast<game_object*>(obj_a->getUserPointer()) );
					}
				}

				if( new_contacts.find(obj_a) == new_contacts.end() )
				{
					if(obj_a->getUserPointer())
					{
						if( static_cast<game_object*>(obj_a->getUserPointer())->get_check_collision() )
							new_contacts[obj_a] = std::make_pair<game_object*, game_object*>( static_cast<game_object*>(obj_a->getUserPointer()), 
																							  static_cast<game_object*>(obj_b->getUserPointer()) );
					}
				}
			}
		}
	}

	std::map< btCollisionObject*, std::pair<game_object*, game_object*> >::iterator it;
	if( !new_contacts.empty() )
	{
		for(  it = new_contacts.begin(); it != new_contacts.end(); it++ )
		{
			if( contacts_.find( (*it).first ) == contacts_.end() )
			{
				if( (*it).second.first->get_check_collision() )
					(*it).second.first->on_start_collision( (*it).second.second );
			}
			else
			{
				if( (*it).second.first->get_check_collision() )
					(*it).second.first->on_collision( (*it).second.second );
			}
		}
	}

	if( !contacts_.empty() )
	{
		for( it = contacts_.begin(); it != contacts_.end(); it++ )
		{
			if( new_contacts.find( (*it).first ) == new_contacts.end() )
			{
				if( (*it).second.first->get_check_collision() )
					(*it).second.first->on_end_collision( (*it).second.second );
			}
		}
	}

    contacts_ = new_contacts;

Re: Collision callbacks questions

Posted: Tue Oct 13, 2009 1:20 pm
by Flix
To Fred_FS who wrote:
I am using a very similar method to check for collisions but I get some problems with rigid bodys that are within other bodys.
So I have something like a trigger which bekongs to another object, but in this trigger is another object. But this smaller object is not registered to collide with my player.
Do you know how to solve this problem?
Strange stuff. From your code if a body has an user ptr, it's casted to your own implementation of btRigidBody, otherwise it's skipped. Maybe one of your bodies is a btGhostObject or a soft body? I have a similiar experience with soft bodies (they don't seem to appear in the contact manifolds at all). Otherwise it can be that you filter some of the objects with some collision flag so that they're discarded early. Or it can be a fault in the Bullet library...

To everybody:
There's another thread here about collision management:
I'm going to post my implementation there.
Maybe it can be useful for somebody...

Re: Collision callbacks questions

Posted: Wed Oct 14, 2009 8:35 am
by Fred_FS
It is not an own implementation of btRigidBody. In my class only an instance of btRigidBody is implemented.
I am just using rigid bodies. Some of the objects have the flag "CF_NO_CONTACT_RESPONSE", but this is only to disable collision. Usually the contact callback will be called in any way. Only if one of these objects is inside another the collision seems not to work. But sometimes it works. So if I try to collide with this object more than one times, the collision callback is working.
So are there maybe any standard flags I have to set or something I could have missed?

Re: Collision callbacks questions

Posted: Thu Oct 15, 2009 11:26 am
by Flix
To Fred_FS:
Some of the objects have the flag "CF_NO_CONTACT_RESPONSE", but this is only to disable collision.
Yes, CF_NO_CONTACT_RESPONSE should report manifold collision points, and I suppose you use a btRigidBody with it (not simply a btCollisionObject that could be skipped by your collision system).
So are there maybe any standard flags I have to set or something I could have missed
Mmmh, if you're not raycasting and you have not excluded collision between bodies with masks yourself, I think that everything should work.

The strange thing is that you say that sometimes the collision is reported and sometimes not: so maybe you should check ifthe collision system you posted works when the body to monitor is at the left, right or both arguments (I mean when you monitor 2 bodies). But still you'd most likely have experimented weird behavior in other cases too, it this is the problem.

Maybe it's a bug in the library, but if I were you I'd try to write a little Bullet Demo to reproduce the problem (if you want you can modify the code I posted here: http://www.bulletphysics.com/Bullet/php ... f=9&t=1691).

If the error persists you can post a bug report to the Bullet developers.

[edit] One thing: have you tried activating all the bodies so that they are not sleeping? Maybe if you start with sleeping objects in contact the manifold is not updated, and when a 3rd object collide with it it wakes it up and everything bahaves normally (Just a last minute guess, more than an answer...)

Regards.

Re: Collision callbacks questions

Posted: Sat Oct 17, 2009 8:35 am
by Fred_FS
Maybe it is a feature ;)
It looks like every single object is able to get only one contact manifold.
So the player gets the collision with the big object, but not with the small obnject within except on sometimes, if the collision with the small object is active, but not the collision with the big object.

Re: Collision callbacks questions

Posted: Thu Oct 22, 2009 1:28 am
by Mattg
Check btCollisionDispatcher::setNearCallback()

Re: Collision callbacks questions

Posted: Sat Oct 24, 2009 11:16 am
by Zeal
So I am still a little confused... can anyone please explain how you are supposed to implement a collision callback? I need to know what body collided with what other body, and the contact points.

Thanks

Re: Collision callbacks questions

Posted: Sat Oct 24, 2009 3:57 pm
by Zeal
Just saw this in the manual...

Code: Select all

void MyNearCallback(btBroadphasePair& collisionPair,
  btCollisionDispatcher& dispatcher, btDispatcherInfo& dispatchInfo) {
 
    // Do your collision logic here
    // Only dispatch the Bullet collision information if you want the physics to continue
    dispatcher.defaultNearCallback(collisionPair, dispatcher, dispatchInfo);
}
 
mDispatcher->setNearCallback(MyNearCallback);
So I take it this is what I need? The 'collisionPair' will contain info about contact points?

*and just to clarify, the above callback is for when bodies actually collide, where as...

Code: Select all

dynamicsWorld->getPairCache()->setOverlapFilterCallback(filterCallback);
...will be called if two bounding boxes simply overlap?

Re: Collision callbacks questions

Posted: Sun Oct 25, 2009 8:58 am
by Zeal
Bahhh but on closer inspection, the call back is applied to ALL collisions.. That kinda defeats the purpose of a callback no? Is there no way to register a collision call back on a per collision object basis?

Re: Collision callbacks questions

Posted: Wed Oct 28, 2009 3:24 am
by Mattg
From btBroadphasePair you can get the two btCollisionObject in the pair. btCollisionObject's can have a user pointer ( setUserPointer/getUserPointer) which can either contain straight up flags for if something custom should be done for the collision or simply point to your own class which can handle the callback logic.

Re: Collision callbacks questions

Posted: Tue Nov 03, 2009 9:03 pm
by Zeal
In another post Erwin said...
Bullet 2.65 will contain various contact callback demos, that show how to do this most efficiently (avoiding traversing all pairs).
Does anyone know what demo he is talking about? Clearly there is no way to register a collision callback on a per object bases (which is a shame, because it is the most elegant solution imo), so it seems we only have two options..

1.) Iterate over ALL manifolds (like people have been doing in this thread).

or

2.) Register a broadphase and nearphase 'callback' (as described in the manual), and just accept the fact that it will be called on ALL collisions (even the ones you dont care about).

Erwin said in his post that there was a way to do collision callbacks without "traversing all pairs", but I just dont see how it is possible... So what is the "most efficient" way to do this?

Re: Collision callbacks questions

Posted: Wed Nov 04, 2009 4:18 pm
by AlexSilverman
It seems to me that overriding the broad/nearphase functions would result in lots of false positives. Did you perhaps mean registering a ContactAddedCallback? That will get fired for every collision (as you mentioned) but not for every potential collision, as would be the case with the broad/nearphase. To my estimation, the contact added callback looks like the cheapest way to go, but that said, I haven't done any profiled comparisons, so it's just an estimation.

As far as a demo goes, I don't believe there's a demo dedicated to contact callbacks.

- Alex