Ghost Objects elude me! Please help

Omniphage
Posts: 4
Joined: Wed Jun 15, 2011 2:43 pm

Ghost Objects elude me! Please help

Post by Omniphage »

Hello everyone,
How do i get my RigidBodies to penetrate my PairCachingGhostObjects in a way that the PairCachingGhostObject still registers them?

I tried setting the collision flag to "CF_NO_CONTACT_RESPONSE" but my Objects still collide with it.

When I set CollisionGroup and CollisionMask to not collide with the Ghost, then the Penetrating Objects are not registered (e.g. my RigidBodies penetrate it, but the OverlappingPairCache stays empty)

I tried several days now, to create a detector/sensor class that tells me when a RigidBody is at a certain location (volume).
Please help me, as I think I might be going crazy. :)

Edit:

I pasted alot of the code out of an example that I found in this forum.
The updateAction is NOT from btActionInterface, but from one of our own classes. It gets called immediately before the physics tick.

Code Attached:

Code: Select all

AEGhostDetector::AEGhostDetector(AEPhysicsWorld* physWorld)
{
    mBulletWorld= physWorld->getBulletWorld();



    mGhostObject = new btPairCachingGhostObject();
    mGhostObject->setWorldTransform(btTransform(btQuaternion::getIdentity(),btVector3(0,2,0)));
    mBulletWorld->getBroadphase()->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback());
    btCylinderShape* shape = new btCylinderShape(btVector3(btScalar(0.5),btScalar(1.),btScalar(0.7)));	// Here the "full" shape will be used
    mGhostObject->setCollisionShape(shape);
    mGhostObject->setCollisionFlags(btCollisionObject::CF_NO_CONTACT_RESPONSE);

    mBulletWorld->addCollisionObject(mGhostObject,btBroadphaseProxy::SensorTrigger, btBroadphaseProxy::StaticFilter|btBroadphaseProxy::DefaultFilter);


    physWorld->addAction(this);
    //mBulletWorld->addCollisionObject(mGhostObject);




}

void AEGhostDetector::updateAction(btDiscreteDynamicsWorld *bulletWorld, int deltaTimeStep)
{
    btAlignedObjectArray < btCollisionObject* > objsInsidePairCachingGhostObject;	// We might want this to be a member variable...
    btAlignedObjectArray < btCollisionObject* >* pObjsInsideGhostObject = NULL;		// We will store a reference of the current array in this pointer

    const btAlignedObjectArray < btCollisionObject* >& objs = mBulletWorld->getCollisionObjectArray();

    for (int i=0,sz=objs.size();i<sz;i++)
    {
        btCollisionObject* o = objs[i];
        btGhostObject* go = btGhostObject::upcast(o);
        if (go)	{
            objsInsidePairCachingGhostObject.resize(0);
            btPairCachingGhostObject* pgo = dynamic_cast < btPairCachingGhostObject* > (go);	// No upcast functionality...
            if (pgo)	{
                GetCollidingObjectsInsidePairCachingGhostObject(static_cast < btDiscreteDynamicsWorld* > (mBulletWorld),pgo,objsInsidePairCachingGhostObject);
                pObjsInsideGhostObject = &objsInsidePairCachingGhostObject;
            }
            else {
                pObjsInsideGhostObject = &go->getOverlappingPairs();	// It's better not to try and copy the whole array, but to keep a reference to it!
                // Side Note: btAlignedObjectArray < btCollisionObject* > objs = go->getOverlappingPairs(); (at the moment) makes my program crash on my system...
                // Nevermind, that was the wrong way of doing it: btAlignedObjectArray < btCollisionObject* >& objs = go->getOverlappingPairs(); is much better.
            }
            // Here pObjsInsideGhostObject should be valid.

            ProcessObectsInsideGhostObjects(*pObjsInsideGhostObject,pgo);

        }
    }
}

void AEGhostDetector::ProcessObectsInsideGhostObjects(btAlignedObjectArray < btCollisionObject* >& objs, const bool isPairCachingGhostObject)
{
    for (int j=0,jsz=objs.size();j<jsz;j++) {
                btRigidBody* b = btRigidBody::upcast(objs[j]);
                if (b) {
                        b->activate();
                        b->applyCentralImpulse(isPairCachingGhostObject ? btVector3(0,0.5,0) : btVector3(0,0.25,0));
                }
        }
}

void AEGhostDetector::GetCollidingObjectsInsidePairCachingGhostObject(btDiscreteDynamicsWorld* m_dynamicsWorld,btPairCachingGhostObject* m_pairCachingGhostObject,btAlignedObjectArray < btCollisionObject* >& collisionArrayOut)
{
        collisionArrayOut.resize(0);
        if (!m_pairCachingGhostObject || !m_dynamicsWorld) return;
        const bool addOnlyObjectsWithNegativeDistance(true);	// With "false" things don't change much, and the code is a bit faster and cleaner...

        //======================================================================================================
        // I thought this line was no longer needed, but it seems to be necessary (and I believe it's an expensive call):
        m_dynamicsWorld->getDispatcher()->dispatchAllCollisionPairs(m_pairCachingGhostObject->getOverlappingPairCache(), m_dynamicsWorld->getDispatchInfo(), m_dynamicsWorld->getDispatcher());
        // PS: This line is present in "bool btKinematicCharacterController::recoverFromPenetration (btCollisionWorld* collisionWorld)" too, so I guess it can't be skipped...
        //======================================================================================================

        btBroadphasePairArray& collisionPairs = m_pairCachingGhostObject->getOverlappingPairCache()->getOverlappingPairArray();
        const int	numObjects=collisionPairs.size();
        qDebug() << " colliding Objs: " << numObjects;
        static btManifoldArray	m_manifoldArray;
        bool added;
        for(int i=0;i<numObjects;i++)	{
        const btBroadphasePair& collisionPair = collisionPairs[i];
                m_manifoldArray.resize(0);
                if (collisionPair.m_algorithm) collisionPair.m_algorithm->getAllContactManifolds(m_manifoldArray);
                else {	// THIS SHOULD NEVER HAPPEN, AND IF IT DOES, PLEASE RE-ENABLE the "call" a few lines above...
                        printf("No collisionPair.m_algorithm - probably m_dynamicsWorld->getDispatcher()->dispatchAllCollisionPairs(...) must be missing.\n");
                }
                added = false;
                for (int j=0;j<m_manifoldArray.size();j++)	{
                        btPersistentManifold* manifold = m_manifoldArray[j];
                        // Here we are in the narrowphase, but can happen that manifold->getNumContacts()==0:
                        if (addOnlyObjectsWithNegativeDistance)	{
                                for (int p=0,numContacts=manifold->getNumContacts();p<numContacts;p++)			{
                                        const btManifoldPoint&pt = manifold->getContactPoint(p);
                                        if (pt.getDistance() < 0.0) 	{
                                                // How can I be sure that the colObjs are all distinct ? I use the "added" flag.
                                                collisionArrayOut.push_back((btCollisionObject*) (manifold->getBody0() == m_pairCachingGhostObject ? manifold->getBody1() : manifold->getBody0()));
                                                added = true;
                                                break;
                                        }
                                }
                        if (added) break;
                        }
                        else if (manifold->getNumContacts()>0) {
                                collisionArrayOut.push_back((btCollisionObject*) (manifold->getBody0() == m_pairCachingGhostObject ? manifold->getBody1() : manifold->getBody0()));
                                break;
                        }
                }
        }
}
Omniphage
Posts: 4
Joined: Wed Jun 15, 2011 2:43 pm

Re: Ghost Objects elude me! Please help

Post by Omniphage »

I have found a workaround/fix for this.
In btCollisionDispatcher I modified needsCollision() thusly:

Code: Select all

bool	btCollisionDispatcher::needsCollision(btCollisionObject* body0,btCollisionObject* body1)
{
    
        btGhostObject* ghost0 = btGhostObject::upcast(body0);
        btGhostObject* ghost1 = btGhostObject::upcast(body1);
        if(ghost0) return false;
        if(ghost1) return false;
        
	btAssert(body0);
	btAssert(body1);

	bool needsCollision = true;
        
        ...
}

Disclaimer:

I really have no idea as to why this works, I am just glad it does.

also the CF_NO_CONTACT_RESPONSE flag is processed in dispatcher::needsResponse, wich seems to have no effect whatsoever on the "penetratability" of objects.