Sign in to follow this  
Noxil

Bullet - btGhostObject

Recommended Posts

Hello,

I have googled and for quite some time now and i seem to only find the same type of answer.
And the result im getting is so strange.

The goal is to create a trigger volume (for now a box) that should trigger events whenever something enters it.
According to the Bullet, btGhostObject is the way to go for simple triggers.

This is my code for setting up bullet.

m_BulletBroadphase = new btDbvtBroadphase();
m_BulletConfiguration = new btDefaultCollisionConfiguration();
m_BulletDispatcher = new btCollisionDispatcher( m_BulletConfiguration );
m_BulletSolver = new btSequentialImpulseConstraintSolver;
m_BulletDynamicsWorld = new btDiscreteDynamicsWorld( m_BulletDispatcher, m_BulletBroadphase, m_BulletSolver, m_BulletConfiguration );
m_BulletDynamicsWorld->setGravity( btVector3(0.0f, -50.0f, 0.0f) );
m_BulletDynamicsWorld->getPairCache()->setInternalGhostPairCallback( new btGhostPairCallback() );

btGhostObject

// create trigger volume
btTransform world( btQuaternion(rotation.yaw, rotation.pitch, rotation.roll), btVector3(location.x, location.y, location.z) );
m_GhostObject = new btGhostObject();
m_GhostObject->setCollisionShape( new btBoxShape(btVector3(10.0f, 5.0f, 10.0f)) );
m_GhostObject->setWorldTransform( world );
getGameWorld()->getBulletDynamicWorld()->addCollisionObject( m_GhostObject );

....

// check for intersections
btAlignedObjectArray< btCollisionObject * > & pairs = m_GhostObject->getOverlappingPairs();
for( pmInt32 i=0; i<pairs.size(); ++i ) 
{
  ....
}

And finally, the object that i use to test the trigger with

btDefaultMotionState * motionState = new btDefaultMotionState();
btVector3 inertia;
m_Shape = new btBoxShape(btVector3(5.0f, 5.0f, 5.0f));
m_Shape->calculateLocalInertia( m_Mass, inertia );
btRigidBody::btRigidBodyConstructionInfo rigidBodyCI( m_Mass, motionState, m_Shape, inertia );
m_Body = new btRigidBody( rigidBodyCI );

The simulation looks correct, the rigid body spawns highup in the air and falls down correctly.
The btRigidBody is transformed to location(0.0f, 40.0f, 0.0f)
And the trigger is transformed to location(0.0f, 5.0f, 0.0)

The problem im getting is that in the triggers intersection check i instantly get a overlapping pair.
Even though they are really far apart and their AABBs cant intersect.
I also checked their worldTransforms, they indicate that they are positioned correctly. I went as far to even set the interpolatedWorldTransform but
it dident help.

Have anyone else had this problem or am i just missing something basic here?
 

Share this post


Link to post
Share on other sites

I cannot spot directly the mistake you've got, it should work I guess...

However a few weeks ago I had a problem with ghost objects with Collision Shapes that had scaling. It really did not work. After fighting a few battles, I've switched to  btCollisionWorld::ContactResultCallback (see contactTest in btCollisionWorld or btDynamicsWorld for details). It works better for me and the rigid body used for triggering doesn't need to be in the dynamicsWorld for this to work.

Share this post


Link to post
Share on other sites

Yeah, all the informaiton i can find seem to say that im doing it right.
But yet it yeilds strange results :(

I read abit about the contact callback thing.
But i felt hesitant towards it, since even Bullet says the preferred way is to use ghost objects.

Guess i have to do some experiments with it and see what happens :)

 

Share this post


Link to post
Share on other sites

What code do you have inside your getOverlappingPairs loop? From memory the internals of that loop are kind of complicated. 

[edit] Checked my code...
I'm using btPairCachingGhostObject and checking for collisions with something like:

for( int i=0, end=m_ghost->getNumOverlappingObjects(); i != end; ++i )
{
	btCollisionObject* c = m_ghost->getOverlappingObject( i );
	TriggerContactResultCallback results;
	m_world->contactPairTest( m_ghost, c, results );
	if( results.m_hit )
		...
}

 

Share this post


Link to post
Share on other sites

Thanks for explaning.
Tinkering with the code, i think im starting to understand what the actuall problem is...

If i put a log inside the loop i get a hit the first frame, then i stop getting hits.
So im thinking im doing something wrong when im trying to transform the btRigidBody.

This is my naive approach

btTransform world( btQuaternion(p_Rotation.yaw, p_Rotation.pitch, p_Rotation.roll), btVector3(p_Location.x, p_Location.y, p_Location.z) );
m_Body->setWorldTransform( world );
m_Body->getMotionState()->setWorldTransform( world );

 

Share this post


Link to post
Share on other sites

That should be fine for teleporting an object. If you're teleporting an object every frame though, you may want to look into implementing it as a kinematic object instead though -- teleporting an object won't result in good interactions when it collides with other objects, but when moving a kinematic object it will collide as normal.

I found that when I teleport ghosts, I had to notify the broadphase for some reason that I don't understand... :(

m_ghost->setWorldTransform( tx );
if( m_ghost->getBroadphaseHandle() )
	m_world->updateSingleAabb(m_ghost);

I also can't remember why I changed from btGhostObject to btPairCachingGhostObject at some point... 

Share this post


Link to post
Share on other sites

I think for now, im going to simply solve my problem by not allowing triggers to take action for the first frame they are alive.
Sure... Not the best option, but atleast i can move forward for now.

So to sum it up, i thought i had a problem with btGhostObject.
It turned out to be a problem with teleporting objects instead.

Thanks for all the help :) 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this