Little Tutorial on btGhostObject (In Progress)

User avatar
Dr.Shepherd
Posts: 168
Joined: Tue Jan 04, 2011 11:47 pm

Little Tutorial on btGhostObject (In Progress)

Post by Dr.Shepherd »

Hi, all, this is a little tutorial on btGhostObject, and this only provides one way to implement it. I think there should be many ways, whatever, I will revise it later when I got new discoveries.

Introduction to btGhostObject:
When you go through the API documentation, please pay attention to the Inheritance diagram for each class you are searching, Actually it is the most important part of the class.

When you check BtGhostObject, please be aware that it is inherited from btCollisionObject. And Pay attention to btPairCachingGhostObject.
-----btCollisionObject
------------btGhostObject
-------------------btPairCachingGhostObject
------------btRigidObject
------------btSoftObject
So you see, it is at the equal level with the rigidbody and softbody.

And don't mess this btCollisionObject with btCollisionShape.
-----btCollisionShape
----------btConvexShape (This is what most people use, box, capsule, sphere etc)
----------btConcaveShape
----------btCompoundShape

One more little thing: Contact manifold is a small group that contains contact points. When two collision objects collide with each other, there may be one more manifolds between them, and each manifold contains no more than 4 contact points.

Why you want to use btGhostObject:
The reason why you use btGhostObject is that you only want to focus on some objects , to see what it collides with. By this way, you don't need to iterate over all contact manifolds in the dynamics world. You iterate only over the pairs of objects that you are interested in. (Check the tutorial: http://bulletphysics.org/mediawiki-1.5. ... d_Triggers)

However, even if you constrain your iteration to part of the whole world, the contact points information are still stored in the dynamics world cache, which means we still have to look up the allContacManifold to get the contact points we need.
btPersistentManifold is a contact point cache, it stays persistent as long as objects are overlapping in the broadphase.

Let's work it out:
First, you should add the header file into your cpp:

Code: Select all

#include "BulletCollision/CollisionDispatch/btGhostObject.h"
It's not just

Code: Select all

#include "btGhostObject.h"
1. When you are initializing your dynamics world, you should do the following to set up a ghost object:

Code: Select all

ghostObject = new btGhostObject();
		ghostObject->setCollisionShape(new btBoxShape(btVector3(btScalar(50.),btScalar(50.),btScalar(50.))));
		ghostObject->setWorldTransform(groundTransform);
		m_dynamicsWorld->addCollisionObject(ghostObject);
		m_dynamicsWorld->getBroadphase()->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback());	
Don't forget the last line.

2. Use this ghostobject:
What I did is to use it in motorPreTickCallback (you can also find it in the same tutorial)

Setup the motorPreTickCallback:

Code: Select all

	m_dynamicsWorld->setInternalTickCallback(motorPreTickCallback,this,true);
Define the motorPreTickCallback:

Code: Select all

void motorPreTickCallback (btDynamicsWorld *world, btScalar timeStep)
{
  	for(int i = 0; i < ghostObject->getNumOverlappingObjects(); i++)
 	{
                btRigidBody *pRigidBody = dynamic_cast<btRigidBody *>(ghostObject->getOverlappingObject(i));
               // do whatever you want to do with these pairs of colliding objects
        }
If you omit the last line in previous step:

Code: Select all

m_dynamicsWorld->getBroadphase()->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback());
You will receive nothing in motorPreTickCallback. (although there is no actual btGhostPairCallback in my case)

About the Tutorial In the Wiki
If you try to implement the example about btGhostObject given at the tutorial from the Wiki, define your GhostObject as the btPairCachingGhostObject, not just as btGhostObject. Then it should work out.

Code: Select all

m_ghostObject = new btPairCachingGhostObject();
I add up some more comments for the example, hope it can help you understand more easily

Code: Select all

// Prepare for getting all the contact manifolds for one Overlapping Pair
      btManifoldArray   manifoldArray;
// Get all the Overlapping Pair
      btBroadphasePairArray& pairArray = ghostObject->getOverlappingPairCache()->getOverlappingPairArray();
      int numPairs = pairArray.size();

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

         const btBroadphasePair& pair = pairArray[i];
         
         //unless we manually perform collision detection on this pair, the contacts are in the dynamics world paircache: 
//The next line fetches the collision information for this Pair
         btBroadphasePair* collisionPair = dynamicsWorld->getPairCache()->findPair(pair.m_pProxy0,pair.m_pProxy1);
         if (!collisionPair)
            continue;

// Read out the all contact manifolds for this Overlapping Pair
         if (collisionPair->m_algorithm)
            collisionPair->m_algorithm->getAllContactManifolds(manifoldArray);

         for (int j=0;j<manifoldArray.size();j++)
         {
            btPersistentManifold* manifold = manifoldArray[j];

// Check if the first object in the Pair is GhostObject or not.
            btScalar directionSign = manifold->getBody0() == m_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)
		{
// Actually you can get the local information from this Overlapping pair, not just world Position
			const btVector3& ptA = pt.getPositionWorldOnA();
			const btVector3& ptB = pt.getPositionWorldOnB();
			const btVector3& normalOnB = pt.m_normalWorldOnB;
			/// work here
		}
            }
         }
      }
Conclusion

This is just the simplest implementation for btGhostObject, and I try to tell what I have done in my case. Though this is simple, it is enough for my case. Hope anyone can give more suggestions on how to use btGhostObject.

I think Bullet should need such little examples to show how each class works, we can provide our each small example and prepare for future's documentation.

I read through the posts below when I try to find information on this topic:
http://bulletphysics.org/Bullet/phpBB3/ ... f=9&t=3976
http://www.bulletphysics.org/Bullet/php ... 26&start=0