Triggers and game feedback

jp_bt
Posts: 2
Joined: Sat Dec 06, 2008 9:54 pm

Triggers and game feedback

Post by jp_bt »

Hey guys

Quick question about implementing triggers...

In previous games I've worked on triggers always track objects when they enter and when they leave a trigger. This was done using callbacks that notified of object to object collisions. Easy enough.

I can't figure out how to get that same behavior using the Bullet library. The only callbacks that looked remotely useful (gContactAddedCallback, gContactProcessedCallback, and gContactDestroyedCallback) are all per CONTACT point and thus get called many, many times. I'm probably not understanding how to use them correctly (as there is no documentation on them) but it seems the contact destroyed callback is basically worthless. Finally, I am reluctant to do anything that requires me to check per tick the status of these objects. It seems pointless to have callbacks only to fallback on checking per tick (defeats the purpose of the callback...).

I found a few useful posts on the forums but nothing that gave a good solution to it that I could find. It seems like a common enough problem so how have people solved this?

Thanks!
User avatar
Erwin Coumans
Site Admin
Posts: 4221
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA

Re: Triggers and game feedback

Post by Erwin Coumans »

There are many ways to retrieve collision information. The best way is to simply iterate over all contact manifolds, and check if there are contact points.

You don't need to iterate over all pairs of objects, you can use a btGhostObject. See http://www.bulletphysics.com/mediawiki- ... d_Triggers

Hope this helps,
Erwin
jp_bt
Posts: 2
Joined: Sat Dec 06, 2008 9:54 pm

Re: Triggers and game feedback

Post by jp_bt »

That was the latest thing I've tried and it gives decent results but isn't always accurate.

Code: Select all

void CollisionManager::OnInternalTickCallback( btScalar timeStep )
{
   int numManifolds = m_pDispatcher->getNumManifolds( );
   for( int i = 0; i < numManifolds; i++ )
   {
      btPersistentManifold* contactManifold = m_pDispatcher->getManifoldByIndexInternal(i);

      if( contactManifold->getNumContacts( ) > 0 )
      {
          ... Activate triggers here
      }
      else
      {
          ... Deactivate trigger here
      }
   }
}
I get the trigger activations consistently but if my objects exit their collisions too quickly, I miss the deactivation. Could this be a timing issue or something?

Thanks!
B_old
Posts: 79
Joined: Tue Sep 26, 2006 1:10 pm

Re: Triggers and game feedback

Post by B_old »

Hi,
I am trying to implement triggers with bullet and thought I might as well ask in this thread as jp_bt seems to have some experience with ghostobjects. I haven't quite figured out how to use the ghostobjects to make them tell me about a collision. Here is the code I use:

Code: Select all

//somewhere during initialization-----------------------------------
m_broadphase->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback());
//----------------------------------------------------------------

//adding a trigger-------------------------------------------------
btPairCachingGhostObject *trigger = new btPairCachingGhostObject();

//both transform and shape are filled with something meaningful
trigger->setWorldTransform(transform);
trigger->setCollisionShape(shape);

trigger->setCollisionFlags(btCollisionObject::CF_NO_CONTACT_RESPONSE);

m_dynamicsWorld->addCollisionObject(trigger, btBroadphaseProxy::SensorTrigger);
m_triggers.push_back(trigger);
//----------------------------------------------------------------

//trying to get some feedback from the trigger, every frame or so----
//this is taken almost without change from http://www.bulletphysics.com/mediawiki-1.5.8/index.php?title=Collision_Callbacks_and_Triggers
for (size_t i = 0; i < m_triggers.size(); ++i)
{
	btPairCachingGhostObject *ghostObject = m_triggers[i];

	btManifoldArray manifoldArray;

	for (int i = 0; i < ghostObject->getOverlappingPairCache()->getNumOverlappingPairs(); i++)
	{
		manifoldArray.resize(0);

		btBroadphasePair* collisionPair = &ghostObject->getOverlappingPairCache()->getOverlappingPairArray()[i];
			
		if (collisionPair->m_algorithm)
			collisionPair->m_algorithm->getAllContactManifolds(manifoldArray);

		for (int j=0;j<manifoldArray.size();j++)
		{
			btPersistentManifold* manifold = manifoldArray[j];
			btScalar directionSign = manifold->getBody0() == ghostObject ? btScalar(-1.0) : btScalar(1.0);

			for (int p=0;p<manifold->getNumContacts();p++)
			{
				const btManifoldPoint&pt = manifold->getContactPoint(p);

				if (pt.getDistance()<0.f)
				{
               //a breakpoint here will never be reached ;(
					const btVector3& ptA = pt.getPositionWorldOnA();
					const btVector3& ptB = pt.getPositionWorldOnB();
					const btVector3& normalOnB = pt.m_normalWorldOnB;
				}
			}
		}
	}
}
//----------------------------------------------------------------
It is the last part I am not sure about. As I said is taking from the article that briefly mentions triggers. Do I have the Callback interface as the KinematicCharacter does instead?
I would be thankful if anyone could point me in the right direction here!

(Another question entirely: did anyone notice a change of physics behavior going from 2.72 to 2.73 making it seem more "nervous"?)
Last edited by B_old on Thu Dec 18, 2008 11:14 am, edited 1 time in total.
sparkprime
Posts: 508
Joined: Fri May 30, 2008 2:51 am
Location: Ossining, New York

Re: Triggers and game feedback

Post by sparkprime »

B_old wrote: (Another question entirely: did anyone notice a change of physics behavior going from 2.72 to 2.73 making it seem more "nervous"?)
Now that you mention it, I was watching a cube bounce around rather more animatedly than I'm sure they used to. It was a small cube though(.3,.3,.3) so i dismissed it at the time.
User avatar
mirat
Posts: 16
Joined: Thu May 29, 2008 10:47 am

Re: Triggers and game feedback

Post by mirat »

2B_old

Here is mistake (this code is from wiki, I think):

Code: Select all

      btBroadphasePair* collisionPair = &ghostObject->getOverlappingPairCache()->getOverlappingPairArray()[i];
         
      if (collisionPair->m_algorithm)
         collisionPair->m_algorithm->getAllContactManifolds(manifoldArray);
Shoud be (from CharacterDemo):

Code: Select all

		btManifoldArray	manifoldArray;
		btBroadphasePairArray& pairArray = m_ghostObject->getOverlappingPairCache()->getOverlappingPairArray();
		int numPairs = pairArray.size();

		for (int i=0;i<numPairs;i++)
		{
			manifoldArray.clear();

			const btBroadphasePair& pair = pairArray[i];
			
			btBroadphasePair* collisionPair = m_overlappingPairCache->getOverlappingPairCache()->findPair(pair.m_pProxy0,pair.m_pProxy1);
			if (!collisionPair)
				continue;

			if (collisionPair->m_algorithm)
				collisionPair->m_algorithm->getAllContactManifolds(manifoldArray);

			for (int j=0;j<manifoldArray.size();j++)
			{
				btPersistentManifold* manifold = manifoldArray[j];
				for (int p=0;p<manifold->getNumContacts();p++)
				{
					const btManifoldPoint&pt = manifold->getContactPoint(p);
					/// work here
				}
			}
		}
	}

Difference in that we need to get algorithm pointer from broadphase pair, not from ghostobject pair. Pair in ghostobject contains only information about two proxies, m_algorithm is always equal to 0. I don't know why, maybe it's a bug.
B_old
Posts: 79
Joined: Tue Sep 26, 2006 1:10 pm

Re: Triggers and game feedback

Post by B_old »

Mirat:
Thanks for the help! It now works the way I want it. Isn't there a callback function though, that can tell you when new contacts have been added. Do you think that this would be more efficient? Maybe I will look into that.
But right now I am happy about the working solution. Thanks again!
Tristan
Posts: 5
Joined: Fri Jan 02, 2009 1:56 pm

Re: Triggers and game feedback

Post by Tristan »

I've just started using Bullet in the last two days and need a bit of guidance on the best way to approach the following:

I'm trying to simulate 'sticky' balls similar to another thread on this forum however I trying to use a gravitational field around each so that they clump around static objects as well as around themselves.

After reading this post I decided to try and represent the grav fields as ghost objects and balls as dynamic rigid bodies.
Starting with an easy question..

I'm keeping two lists, one of the balls and another of corresponding grav ghosts and manually updating the ghost positions each cycle using the ball motion states.
Is there a better way of attaching the ghosts to the rigid bodies?

My main question is how to filter and check collisions correctly as I’m having problems picking up the ghost collisions.
When a grav ghost comes into contact with another grav ghost or with a static object then I need to do stuff so ...

I'm creating static objects like this, so that they collide with kinematic and sensor triggers

Code: Select all

	m_seedbody = CreateRigidBody(0.0f, startTransform,m_trimeshShape,btBroadphaseProxy::StaticFilter,btBroadphaseProxy::KinematicFilter | btBroadphaseProxy::SensorTrigger);
and ball objects with grav ghosts like this...(apologies for bad naming, I'm not a programmer)

Code: Select all


btRigidBody* CDemo::CreateSphereObj(btVector3& pos,float rad)
{

	btCollisionShape* pshape = new btSphereShape(rad);
	m_shapes.push_back(pshape);

	btTransform startTransform;
	startTransform.setIdentity();
	startTransform.setOrigin(pos);

	float mass = BALLDENS*1.333f*M_PI*rad*rad*rad;

       //collides with kinematic and static objects
	btRigidBody* body = this->CreateRigidBody(mass, startTransform,pshape, btBroadphaseProxy::KinematicFilter,btBroadphaseProxy::KinematicFilter | btBroadphaseProxy::StaticFilter );
	
	m_spheres.push_back(body);

	btCollisionShape* pshape2 = new btSphereShape(rad*GRAVINF);
	m_shapes.push_back(pshape2);

	btPairCachingGhostObject* field = new btPairCachingGhostObject();
	field->setWorldTransform(startTransform);
	field->setCollisionShape(pshape2);

       //collides with other sensors and static objects
	m_dynamicsWorld->addCollisionObject(field, btBroadphaseProxy::SensorTrigger,btBroadphaseProxy::SensorTrigger | btBroadphaseProxy::StaticFilter);
       //not sure what the following line does but it currently doesnt make any difference
	//field->setCollisionFlags(btCollisionObject::CF_NO_CONTACT_RESPONSE);
	m_fields.push_back(field);

	return body;
}
My ghost collision pair detection is similar to the snippets on this thread however currently I'm not even getting a single pair.

Code: Select all


void	CDemo::ProcessContacts()
{

	for (int f=0;f<m_fields.size();f++)
	{
		btPairCachingGhostObject* field  = m_fields[f]; 
		btManifoldArray   manifoldArray;
                btBroadphasePairArray& pairArray = field->getOverlappingPairCache()->getOverlappingPairArray();
		int numPairs = pairArray.size();
		for (int i=0;i<numPairs;i++)
		{
                       //not getting here
			manifoldArray.clear();
			const btBroadphasePair& pair = pairArray[i];
			btBroadphasePair* collisionPair = m_broadphase->getOverlappingPairCache()->findPair(pair.m_pProxy0,pair.m_pProxy1);
			if (!collisionPair)
                             continue;
                       //.........

		}
	}
}
Any help would be much appreciated.
Thanks
Tristan
Posts: 5
Joined: Fri Jan 02, 2009 1:56 pm

Re: Triggers and game feedback

Post by Tristan »

Sorted!
I forgot to add....

Code: Select all

m_broadphase->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback());
...after the ghost creation.
Works a dream, thanks Erwin.
AndrewWillmott
Posts: 2
Joined: Tue Jan 13, 2009 9:27 am

Re: Triggers and game feedback

Post by AndrewWillmott »

(Another question entirely: did anyone notice a change of physics behavior going from 2.72 to 2.73 making it seem more "nervous"?)
I don't know if this is the same thing you're talking about, but I noticed the BasicDemo cubes were much more jittery when in their rest state than previously. (Noticeably so, particularly if you zoom the camera in a little.)

However when I dug into it, it turned out that in the 2.73 demo the cubes had been scaled down by a factor of 10 -- see the SCALING define at the top of BasicDemo.cpp. If you make the same change to the 2.72 demo, you see very similar behaviour. So it's not a simulation engine regression in this case.
B_old
Posts: 79
Joined: Tue Sep 26, 2006 1:10 pm

Re: Triggers and game feedback

Post by B_old »

AndrewWillmott wrote: I don't know if this is the same thing you're talking about, but I noticed the BasicDemo cubes were much more jittery when in their rest state than previously. (Noticeably so, particularly if you zoom the camera in a little.)

However when I dug into it, it turned out that in the 2.73 demo the cubes had been scaled down by a factor of 10 -- see the SCALING define at the top of BasicDemo.cpp. If you make the same change to the 2.72 demo, you see very similar behaviour. So it's not a simulation engine regression in this case.
Hm. I noticed different behavior in my own application and did not change the scale of anything. Maybe there is something else that I forgot and is important in 2.73. Don't kow...
sparkprime
Posts: 508
Joined: Fri May 30, 2008 2:51 am
Location: Ossining, New York

Re: Triggers and game feedback

Post by sparkprime »

The behaviour of boxes that i mentioned above was actually due to me switching from static plane to triangle mesh for my floor.