Collision callbacks questions

garvek
Posts: 6
Joined: Tue Aug 25, 2009 10:26 pm

Collision callbacks questions

Post 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.
Last edited by garvek on Thu Aug 27, 2009 10:30 pm, edited 3 times in total.
garvek
Posts: 6
Joined: Tue Aug 25, 2009 10:26 pm

Re: Misunderstanding of collision callbacks

Post 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
kidchaos2k9
Posts: 3
Joined: Mon Jul 27, 2009 10:19 am

Re: Collision callbacks questions

Post 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^)>
Fred_FS
Posts: 10
Joined: Sun Sep 27, 2009 9:56 am

Re: Collision callbacks questions

Post 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;
Flix
Posts: 456
Joined: Tue Dec 25, 2007 1:06 pm

Re: Collision callbacks questions

Post 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...
Fred_FS
Posts: 10
Joined: Sun Sep 27, 2009 9:56 am

Re: Collision callbacks questions

Post 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?
Flix
Posts: 456
Joined: Tue Dec 25, 2007 1:06 pm

Re: Collision callbacks questions

Post 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.
Fred_FS
Posts: 10
Joined: Sun Sep 27, 2009 9:56 am

Re: Collision callbacks questions

Post 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.
Mattg
Posts: 12
Joined: Thu Oct 22, 2009 12:50 am

Re: Collision callbacks questions

Post by Mattg »

Check btCollisionDispatcher::setNearCallback()
Zeal
Posts: 47
Joined: Thu Oct 18, 2007 6:49 am

Re: Collision callbacks questions

Post 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
Zeal
Posts: 47
Joined: Thu Oct 18, 2007 6:49 am

Re: Collision callbacks questions

Post 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?
Zeal
Posts: 47
Joined: Thu Oct 18, 2007 6:49 am

Re: Collision callbacks questions

Post 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?
Mattg
Posts: 12
Joined: Thu Oct 22, 2009 12:50 am

Re: Collision callbacks questions

Post 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.
Zeal
Posts: 47
Joined: Thu Oct 18, 2007 6:49 am

Re: Collision callbacks questions

Post 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?
AlexSilverman
Posts: 141
Joined: Mon Jul 02, 2007 5:12 pm

Re: Collision callbacks questions

Post 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
Post Reply