Not getting all collisions in PhysicsCollisionListener

Hello all,

I am not sure if I am misunderstanding how to use JBullet, but I am not getting the collision events that I am expecting. I have constructed a simple example that illustrates the type of thing I want to do and I will post the code below. In the example a have a floor and two balls. I apply an impulse to one ball so that they will collide. My listener gets the events for the collisions between each of the balls and the floor, but no event for the collision between the balls. It is clear that the collision is occurring since it can be viewed, so I do not understand why the listener does not get an event for it.

Also, I tried running TestCollisionListener from JmeTests and I seem to not get the events there either, so I am wondering if it is a problem with the version of JME I am using. The version of the SDK I am using is v3.2.1-stable-sdk3.

Thanks in advance.

Here is the code :

public class Main extends SimpleApplication
{
    private PhysicsCollisionListener myCollisionListener = new PhysicsCollisionListener()
    {
        @Override
        public void collision(PhysicsCollisionEvent event)
        {
//            if (!(event.getObjectB().getCollisionShape() instanceof PlaneCollisionShape))
            {
                System.err.println(event.getObjectA().getCollisionShape().getObjectId()
                    + " :: " + event.getObjectB().getCollisionShape().getObjectId());
            }
        }
    };

    public static void main(String[] args)
    {
        Main app = new Main();
        app.setShowSettings(false);
        AppSettings settings = new AppSettings(true);
        settings.setWidth(1768);
        settings.setHeight(992);
        settings.setFrameRate(60);
        app.setSettings(settings);
        app.start();
    }

    private static Sphere mySphere;

    @Override
    public void simpleInitApp()
    {
        getFlyByCamera().setEnabled(false);

        createMaterial();
        createBulletAppState();
        createFloor();

        Vector3f camLoc = new Vector3f(0f, 80f, 220f);
        cam.setLocation(camLoc);
        Quaternion quat = new Quaternion();
        quat.lookAt(camLoc.mult(-1f), Vector3f.UNIT_Y);
        cam.setRotation(quat);

        float radius = 3f;
        mySphere = new Sphere(32, 32, radius, true, false);
        mySphere.setTextureMode(Sphere.TextureMode.Projected);

        RigidBodyControl ballBodyA = createBall(3);
        ballBodyA.setPhysicsLocation(new Vector3f(0f, 3f, 0f));

        RigidBodyControl ballBodyB = createBall(3);
        ballBodyB.setPhysicsLocation(new Vector3f(40f, 3f, 0f));

        ballBodyA.applyImpulse(new Vector3f(20f, 0, 0), Vector3f.ZERO);
    }

    BulletAppState myBulletAppState;

    public void createBulletAppState()
    {
        myBulletAppState = new BulletAppState();
        myBulletAppState.setEnabled(true);
        myBulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL);
        stateManager.attach(myBulletAppState);
        myBulletAppState.getPhysicsSpace().addCollisionListener(myCollisionListener);
    }

    public void createFloor()
    {
        Box floorBox = new Box(140f, 0.25f, 140f);
        Geometry floorGeometry = new Geometry("Floor", floorBox);
        floorGeometry.setMaterial(myMaterial);
        floorGeometry.setLocalTranslation(0f, -0.25f, 0f);
        Plane plane = new Plane();
        plane.setOriginNormal(Vector3f.ZERO, Vector3f.UNIT_Y);
        RigidBodyControl floorBody = new RigidBodyControl(new PlaneCollisionShape(plane), 0);
        floorGeometry.addControl(floorBody);
        rootNode.attachChild(floorGeometry);
        myBulletAppState.getPhysicsSpace().add(floorGeometry);
    }

    Material myMaterial;

    public void createMaterial()
    {
        myMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        Texture tex = assetManager.loadTexture("Textures/fabric1.jpg");
        tex.setWrap(Texture.WrapMode.Repeat);
        myMaterial.setTexture("ColorMap", tex);
    }

    public RigidBodyControl createBall(float radius)
    {
        Geometry ball = new Geometry("ball", mySphere);
        ball.setMaterial(myMaterial);
        SphereCollisionShape collShape = new SphereCollisionShape(radius);
        RigidBodyControl ballBody = new RigidBodyControl(collShape);
        ball.addControl(ballBody);
        rootNode.attachChild(ball);
        myBulletAppState.getPhysicsSpace().add(ballBody);
        return ballBody;
    }
}

See if not running in parallel mode fixes the problem.

I only say this because I recently had some collision listener weirdness related to which thread did what (in a custom bullet app state)… specifically with the “not really support” jbullet. In my case, I wasn’t getting any collisions at all.

@pspeed Thanks for the suggestion. I tried switching that to ThreadingType.SEQUENTIAL, but still no luck.

I also tried adding

 ballBody.setCollisionGroup(PhysicsCollisionObject.COLLISION_GROUP_03);
 ballBody.addCollideWithGroup(PhysicsCollisionObject.COLLISION_GROUP_03);

Which yields the same result.

Just doing the first line without the second, causes the balls to pass through each other as I would expect.

The bit that really stumps me here is that you can see the collision occur and all the the behavior seems to look right on-screen. Just no collision event is delivered to the listener.

EDIT : @pspeed After some more testing, it seems like this only happens when both of geometries use SphereCollisionShape. If one or both of the balls is switched to use CapsuleCollisionShape or BoxCollisionShape, then all events are received as expected.

EDIT 2 : I played with this some more and I am convinced that this is bug in the physics engine. This behavior only occurs with both collision shapes are SphereCollisionShape and does not occur for any of the other collision shapes. Also, it makes no difference if you use RigidBodyControl or GhostControl.

@pspeed So, this is not so much a problem for me now that I can work around it. I am using a CapsuleCollisionShape with a height of 0. But I wanted to ask if I should be doing something more in the interest of being a good community member. The code in my original post reliably reproduces this problem, should I submit a bug report/ticket somehow?

Yeah, sure. If it’s a bug in bullet then I’m not sure there is much we can do about it but it might as well be tracked.

One thing I notice is that all of your spheres are static.

…static objects won’t collide with other static objects. Else the whole world would generate collision events all the time.

Edit: nevermind… I think RigidBodyControl defaults to mass 1?

Edit 2: the issue is that locally I do not see this behavior in my own code… though at the moment I have to use jbullet for testing and haven’t tried native bullet yet.

I won’t be able to mess with it for a couple of days, but I’ll try switch my environment to jbullet this weekend and see how it goes.

Edit:
@pspeed I realized that switching to jbullet really wouldn’t accomplish much, so I am probably not going to do that. I did verify that RigidBodyControl uses a default mass of 1 and I tried changing that to see if it makes any difference, but it didn’t change anything. I also tried changing the stationary ball to have mass 0.

I am going to hold off on writing a ticket for it until someone else can reproduce the problem. If you can think of anything else you’d like try out, just let me know.

@pspeed I just wanted to post an update, since I discovered something new. I was doing some testing on Linux and do not have this problem on there, the problem only occurs for me on Windows. So, it may be a problem with the native libs for that platform, or some other environmental issue on Windows.

One more curiosity, when I change the collision group and the collide with for the balls, shouldn’t they fall though the floor since it would no longer be in the same collision group as the floor? Or maybe I am misunderstanding how the collision groups work?