How do you use Ghost Objects?

JohnnyM
Posts: 15
Joined: Tue Dec 23, 2008 11:51 pm

How do you use Ghost Objects?

Post by JohnnyM »

The only information I could find on how to use the btGhostObject was in the Collision Callbacks and Triggers Tutorial, but it must be out of date or something because the getOverlappingPairCache() function doesn't exist for the ghost object in 2.73 sp1. Also that tutorial explains nothing about how to set up a ghost object.

I tried setting up a ghost object like this:
btGhostObject* ghostObject = new btGhostObject();
ghostObject->setCollisionShape(new btSphereShape(5));
ghostObject->setWorldTransform(btTransform(btQuaternion(0,0,0,1),btVector3(0,5,0)));
dynamicsWorld->addCollisionObject(ghostObject);
All this did was create an invisible sphere that things collide with.

Can anyone help me out?

Thanks.
mickey
Posts: 107
Joined: Fri Sep 19, 2008 6:08 pm

Re: How do you use Ghost Objects?

Post by mickey »

Hi

I use the btGhostObject to apply impulses to rigid bodies like so:

Code: Select all

		for(int i = 0; i < m_pGhostObject->getNumOverlappingObjects(); i++)
		{
			// Dynamic cast to make sure its a rigid body
			btRigidBody *pRigidBody = dynamic_cast<btRigidBody *>(m_pGhostObject->getOverlappingObject(i));			
			if(pRigidBody)
			{
				pRigidBody->activate(true);
				pRigidBody->applyCentralImpulse(rayTo);
			}
		}
rayTo is just the direction I want the impulse to go towards to. Basically I position the btGhostObject in the world, then I use its function to go through all object that it overlaps.

Hope that helps.
JohnnyM
Posts: 15
Joined: Tue Dec 23, 2008 11:51 pm

Re: How do you use Ghost Objects?

Post by JohnnyM »

Thanks, that will help once I manage to make a working ghost object, but I haven't even made it that far. I can make one, but how do I put it in a dynamics world and give it a collision shape?
mreuvers
Posts: 69
Joined: Sat May 10, 2008 8:39 am

Re: How do you use Ghost Objects?

Post by mreuvers »

JohnnyM wrote:Thanks, that will help once I manage to make a working ghost object, but I haven't even made it that far. I can make one, but how do I put it in a dynamics world and give it a collision shape?
You already did ;-)

Code: Select all

ghostObject->setCollisionShape(new btSphereShape(5));
...
dynamicsWorld->addCollisionObject(ghostObject);
Using this ghostobject you should be able to detect all other objects that collide with this ghostobject. This is useful if you want to create volumetric triggers, explosions etc. Please note that the ghostobjects don't have collision response, nor will any colliding object respond to the object. It's simply a collision detection mechanism.
Last edited by mreuvers on Sun Jan 11, 2009 10:48 am, edited 1 time in total.
JohnnyM
Posts: 15
Joined: Tue Dec 23, 2008 11:51 pm

Re: How do you use Ghost Objects?

Post by JohnnyM »

For some reason mine had contact response, but I discovered the setCollisionFlag function, so now it all works good.

Thanks.
JohnnyM
Posts: 15
Joined: Tue Dec 23, 2008 11:51 pm

Re: How do you use Ghost Objects?

Post by JohnnyM »

Now there are no overlapping objects though. Any idea why? I'm creating the object just the same and I definitely have lots of other objects moving through it.
JohnnyM
Posts: 15
Joined: Tue Dec 23, 2008 11:51 pm

Re: How do you use Ghost Objects?

Post by JohnnyM »

Bump.

Anyone have any ideas? I really need to figure this out because I need explosions for my project. Also, I'm using the btSoftRigidDynamicsWorld if that makes any difference. I have the same problem with the btDiscreteDynamicsWorld though. Could someone post a block of code that works for them?
devmelon
Posts: 19
Joined: Thu Nov 27, 2008 1:44 pm

Re: How do you use Ghost Objects?

Post by devmelon »

I would also like to know how to use Ghost Objects.

Maybe I should explain what I am trying to achieve here, just in case I'm looking for another tool to hammer my nails with...

Current approach and problems
Our project has objects with varying properties. Some can set fire to other objects, others can be collected by the player such as powerups. All in all, the objects interact with each other through collisions. Currently we have tested techniques using gContactAddedCallback, but we would also like to know when the contact is "released". On/Off. 1/0.

While we can sense when an object have collided, we can't make out when it no longer collides. gContactDestroyedCallback sounds like our candidate but the only parameter is a void* and we haven't found more documentation on this. As far as I can tell, we can't make out which contact is destroyed through a void*.

Also, this approach has more shortcomings, such as it reports several contacts when we only need to know if at all any collision has occured.

Collision Report Requirements
At our current state I think our project requirements are boiled down to:
  • Should report contact "on" between objects
  • Should report contact "off" between objects
  • Should use a shape, not a AABB (I read that ghost objects use AABB by default)
Ghost Objects?
How are Ghost Objects supposed to be used? Can they help achieve what we're trying to do? What do I need to do to get callbacks when certain objects collide?
pico
Posts: 229
Joined: Sun Sep 30, 2007 7:58 am

Re: How do you use Ghost Objects?

Post by pico »

devmelon wrote:I would also like to know how to use Ghost Objects.

While we can sense when an object have collided, we can't make out when it no longer collides. gContactDestroyedCallback sounds like our candidate but the only parameter is a void* and we haven't found more documentation on this. As far as I can tell, we can't make out which contact is destroyed through a void*.
Hi,

the void* parameter is actually the m_userPersistentData from the manifold. You can use this user only property for a pointer to your internal object.
devmelon
Posts: 19
Joined: Thu Nov 27, 2008 1:44 pm

Re: How do you use Ghost Objects?

Post by devmelon »

pico wrote:Hi,

the void* parameter is actually the m_userPersistentData from the manifold. You can use this user only property for a pointer to your internal object.
Thanks!

May I ask where you learned about it? I am not sure I navigate the documentation as it is intended :)
pico
Posts: 229
Joined: Sun Sep 30, 2007 7:58 am

Re: How do you use Ghost Objects?

Post by pico »

Hi,

after seeing the void* called userPersistentData i simply searched in the callback source where it comes from. The demos and sources are really needed to understand bullet. Along with the manual and the (sometimes wrong/unspecific) wiki you won't come too far.
devmelon
Posts: 19
Joined: Thu Nov 27, 2008 1:44 pm

Re: How do you use Ghost Objects?

Post by devmelon »

pico wrote:Hi,

after seeing the void* called userPersistentData i simply searched in the callback source where it comes from. The demos and sources are really needed to understand bullet. Along with the manual and the (sometimes wrong/unspecific) wiki you won't come too far.
It appears as if the amount of calls to gContactDestroyedCallback doesn't match the number of calls to gContactAddedCallback. We implemented trigger on/off using the userPersistantData in the manifold, but we always got more calls to the Add callback than the Remove callback. To make sure our algorithms wasn't interfering with the callbacks, I simply added a [int] mBalance = 0; to keep track of calls. For each Added call, I'd mBalance++; and for each Remove mBalance--;. The result should be mBalance == 0 when no contacts are present, but mBalance just keeps growing and growing over the thousands. mBalance drops occasionally but nowhere near as often as it rises.

Any thoughts about this?

I hope I've just done something wrong and not that it is a major issue.

EDIT

It appears as if gContactAddedCallback is called several times for a single contact even if it is not destroyed in between. Checking if I've set my userdata on the incoming btManifoldPoint solves the problem, as newly created contact points initialize the user pointer to NULL. It works as expected now. I guess this has to do with something like that the contact point could have changed location, and then the callback is triggered once again.
pico
Posts: 229
Joined: Sun Sep 30, 2007 7:58 am

Re: How do you use Ghost Objects?

Post by pico »

devmelon wrote:
pico wrote:Hi,

after seeing the void* called userPersistentData i simply searched in the callback source where it comes from. The demos and sources are really needed to It appears as if gContactAddedCallback is called several times for a single contact even if it is not destroyed in between. Checking if I've set my userdata on the incoming btManifoldPoint solves the problem, as newly created contact points initialize the user pointer to NULL. It works as expected now. I guess this has to do with something like that the contact point could have changed location, and then the callback is triggered once again.
Hi,

i think each manifold has also a lifetime you can check for this purpose.
AndrewWillmott
Posts: 2
Joined: Tue Jan 13, 2009 9:27 am

Re: How do you use Ghost Objects?

Post by AndrewWillmott »

Just in case others come across this thread, the likely issue for the original poster was that, as well as creating a ghost object and registering it with the collision world, you need to register a ghost pair callback to activate the world's ghost functionality. You can do that during initial setup with something like:

Code: Select all

broadPhase->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback());
GameQ
Posts: 8
Joined: Fri Aug 14, 2009 8:44 pm

Re: How do you use Ghost Objects?

Post by GameQ »

Has anyone ran into a problem where the btGhostObjects pair array isn't initialized correctly?

I've been trying to set up a simply demo of a ghostObject and one rigid body passing through it.

My ghostObj->getNumOverlappingPairs() always return me the value of 0xcdcdcdcd.

this is my set up code for the ghostObj

Code: Select all

                //create ghost object
		ghostObj = new btGhostObject();
		btCollisionShape* shape = new btBoxShape(btVector3(5,5,5));
		ghostObj->setCollisionShape(shape);
		btTransform trans;
		trans.setIdentity();
		trans.setOrigin(btVector3(0,6,0));
		//btQuaternion quat;
		//quat.setEuler(45,45,45);
		//trans.setRotation(quat);
		ghostObj->setWorldTransform(trans);
		ghostObj->setCollisionFlags(ghostObj->getCollisionFlags() | btCollisionObject::CF_NO_CONTACT_RESPONSE);
		ghostObj->getOverlappingPairs().size(); //this returns value of 0xcdcdcdcd and not 0
		czGetDynamicsWorld()->addCollisionObject(ghostObj);

                czGetDynamicsWorld()->getBroadphase()->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback());
I do a quick test of the size() function and it returns a corrupt value there

My overlapping test is this:

Code: Select all

int numObjectsInGhost = 0;
numObjectsInGhost = ghostObj->getNumOverlappingObjects(); //numObjectsInGhost is set to 0xcdcdcdcd
czPrintf("number of objects inside ghost: %d\n", numObjectsInGhost);
for(int i=0; i<numObjectsInGhost;++i)
{
	btCollisionObject* obj = ghostObj->getOverlappingObject(i);
	czPrintf("obj[%d] = %p\n",i, obj);
}
Now for the very scary part. If I set a break point at:

numObjectsInGhost = ghostObj->getNumOverlappingObjects();

Then step into this function, I am brought to this:

Code: Select all

int	getNumOverlappingObjects() const
{
	return m_overlappingObjects.size();
}
Mousing over overlappingObjects shows me that m_size is in fact 0, and when I break the program when the rigid body is inside the ghost it shows it as 1. So it looks like it works, but then I step into the size() function which brings me to

Code: Select all

/// return the number of elements in the array
SIMD_FORCE_INLINE	int size() const
{	
	return m_size;
}
and guess what m_size if? it 0xcdcdcdcd!!! I don't really understand. I went into my Memory watcher and put in the address of m_overlappingObjects. Doing this I see that the first 4 bytes are in deed 0xcdcdcdcd. This leads me to believe that m_allocator is corrupted somehow since that is the only thing that is declared before m_size.

Just for extra info I'm using Microsoft Visual Studio 2008. When I mouse over that m_overlappingObjects when the rigid body is not in the ghostObj this is the full results:
m_allocator {...}
m_size 0
m_capacity 0
m_data 0x00000000
m_ownMemory true

When I mouse over with the rigid body inside it I get this:
m_allocator {...}
m_size 1
m_capacity 1
m_data 0x00281bb0 //Yes that IS the address of my rigidBody
m_ownMemory true

but m_overlappingObjects.size() always returns the value of 0xcdcdcdcd (which is -842150451 in case your wondering).

I'm so lost as to why this doesn't work ):

~GameQ
Post Reply