1

I'm trying to do a 3D collision test with Bullet, which I would have expected to work fairly simply:

@Override
public void create(){
   . . .
   /*
    * Collision
    */

   collisionConfig=new btDefaultCollisionConfiguration();
   dispatcher=new btCollisionDispatcher(collisionConfig);
   broadphase=new btDbvtBroadphase();
   world=new btCollisionWorld(dispatcher, broadphase, collisionConfig);
   contactListener=new PiscesContactListener();
   contactListener.enable();

   /*
    * Test stuff
    */

   btSphereShape sphere=new btSphereShape(2.5f);
   btCollisionObject object1=new btCollisionObject();
   btCollisionObject object2=new btCollisionObject();
   object1.setCollisionShape(sphere);
   object2.setCollisionShape(sphere);
   object1.setWorldTransform(new Matrix4(new Vector3(0f, 0f, 0f), new Quaternion(0f, 0f, 0f, 0f), new Vector3(1f, 1f, 1f)));
   object2.setWorldTransform(new Matrix4(new Vector3(1f, 0f, 0f), new Quaternion(0f, 0f, 0f, 0f), new Vector3(1f, 1f, 1f)));
   object1.setUserValue(0);
   object2.setUserValue(1);
   object1.setCollisionFlags(WorldObject.COLLISION_PRIMARY);   // 1<<9
   object2.setCollisionFlags(WorldObject.COLLISION_PRIMARY);
   world.addCollisionObject(object1, WorldObject.COLLISION_PRIMARY, WorldObject.COLLISION_EVERYTHING);   // -1
   world.addCollisionObject(object2, WorldObject.COLLISION_PRIMARY, WorldObject.COLLISION_EVERYTHING);
   . . .
}

@Override
public void render() {
   . . .
   world.performDiscreteCollisionDetection();
   . . .
}

/*
 * In a separate file
 */
public class PiscesContactListener extends ContactListener {   
    public boolean onContactAdded (int userValue0, int partId0, int index0, boolean match0, int userValue1, int partId1, int index1, boolean match1) {
        System.out.println("Collision detected between "+userValue0+" and "+userValue1);
        return true;
    }
}

(I followed this guide, though I obviously deviated from it a little to try to make it even simpler.)

A 2.5-unit sphere at (0, 0, 0) and a 2.5-unit sphere at (1, 0, 0) should cause a collision, should they not? Nothing's appearing in the console window.

I somewhat suspect there's something fundamental that I'm forgetting, since I tried to do a raycast and that isn't working either.

It's probably worth mentioning that calling world.drawDebugWorld(); draws wireframes of all the objects where they would be expected to be, so now I'm suspecting the error lies in the contact listener or maybe the flags I'm using (though I haven't had any luck with any other collision flags). Am I missing something in the contact listener?

Also, I tried using a ContactCache instead of a ContactListener but that didn't work either. Most reading I can find on the matter talks about ContactListener so I'm probably better off using that.

I'm obviously forgetting something since other people are able to do this, can anyone point out what that might be?

Dragonite
  • 35
  • 1
  • 6

1 Answers1

2

You are mixing collision flags (btCollisionObject#setCollisionFlags(int *flags*)) and collision filtering (btCollisionWorld#addCollisionObject(object, short *group*, short *mask*)). These are two very different things.

You should not call the btCollisionObject#setCollisionFlags(int) method with anything other than the available flags (see here). The CF_CUSTOM_MATERIAL_CALLBACK collision flag must be set for the ContactListener#onContactAdded method to be called. So that's why your code doesn't work as you expected.

Note that in my tutorial you are referring to, this is explained as well:

public void spawn() {
    ...
    obj.body.setUserValue(instances.size);
    obj.body.setCollisionFlags(obj.body.getCollisionFlags() | btCollisionObject.CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
    ...
}

In the spawn method we set this value, using the setUserValue method, to the index of the object in the instances array. And we also inform Bullet that we want to receive collision events for this object by adding the CF_CUSTOM_MATERIAL_CALLBACK flag. This flag is required for the onContactAdded method to be called.

There is no reason to use 1<<11 instead of 1<<9 for collision filtering. You probably changed something else (e.g. the collision flag) as well and wrongfully assumed that this change in the collision filter caused it to start working.

Note that besides collision flags and collision filtering, there is also the (libgdx specific) contact callback filtering (explained in the second part of that tutorial). Keep in mind that those are three totally different and unrelated things.

Xoppa
  • 7,983
  • 1
  • 23
  • 34
  • Interesting, this would likely explain a few other problems I was having, too. Thanks for pointing these out! – Dragonite May 13 '18 at 17:03