Managing collisions

During each simulation step, Bullet performs collision detection in 2 phases: broadphase and narrowphase.

  1. Broadphase enumerates pairs of objects in close proximity, based on overlaps between their axis-aligned bounding boxes (AABBs).

  2. Narrowphase uses detailed collision shapes to test each pair found during broadphase, resulting in a list of manifolds where the shapes intersect.

Each manifold is composed of up to 4 contact points. Bullet’s rigid-body dynamics uses manifolds and contact points to implement contact response, including friction and restitution.

Libbulletjme provides mechanisms to:

  • count or enumerate overlaps,

  • customize which overlaps are handled and which are ignored,

  • access the manifolds and contact points, and

  • perform custom actions when Bullet creates or destroys a manifold or when it processes a contact point.

It also provides mechanisms:

  • to test for intersection between 2 collision objects or

  • to count or enumerate collision objects that intersect with:

    • a specific line segment,

    • a shape in a specific position, or

    • a shape sweeping from one position to another.

Such intersection tests are typically performed between simulation steps. They are useful (for instance) when you want to add a collision object to a space without causing an immediate collision.

Ghosts

A ghost is a collision object without contact response, created solely to detect overlaps with other collision objects. You can create a ghost by invoking the PhysicsGhostObject constructor. In order to work, the ghost must be added to a space.

The constructor allows you to specify a collision shape. However, the details of the shape are unimportant. The key property of a ghost is its axis-aligned bounding box, which is determined by the ghost’s shape and position.

The AABBs generated by Bullet aren’t minimal. Approximations in Bullet make them somewhat larger than necessary. However, they are usually accurate enough to be useful.

HelloGhost is a SPORT app that illustrates how a ghost could be used to detect a character entering/leaving a box-shaped zone.

Things notice while running the app:

  1. The ghost has a spherical shape, but its AABB (in yellow) is box-shaped.

  2. The character has a capsule shape. To clarify what’s going on, its AABB is outlined in white.

  3. Press Right arrow to walk the character toward the ghost.

  4. As soon as the character’s AABB touches the ghost’s AABB, the ghost turns red, even though their collision shapes haven’t intersected yet.

  5. Press Space bar to jump.

  6. The character can jump high enough to leave the ghost’s AABB, at which time the ghost will momentarily turn yellow again.

In addition the counting overlapping objects, you can enumerate them using ghost.getOverlappingObjects().

Filtering AABB overlaps

You might want to prevent collisions from occurring between certain objects, perhaps under specific conditions. Filtering out an overlap during broadphase prevents collisions between the overlapping objects. Libbulletjme provides several mechanisms to implement such filtering.

The wheels of a PhysicsVehicle aren’t collision objects, so these mechanisms don’t affect them.

Using collision groups

You can filter overlaps using collision groups. This is the most efficient filtering mechanism.

16 groups are defined, and each collision object belongs to exactly one group. By default, that group is COLLISION_GROUP_01. To assign an object to a different group, invoke collisionObject.setCollisionGroup().

By default, collision objects collide only with objects in COLLISION_GROUP_01. To alter an object’s collides-with set, invoke collisionObject.setCollideWithGroup().

For a collision to occur between objects X and Y, either X must collide with Y’s group OR Y must collide with X’s group.

Using ignore lists

You can filter AABB overlaps on a pair-by-pair basis by creating ignore lists for specific collision objects. Ignore lists are more flexible than collision groups, but less efficient.

Each collision object is created with an empty ignore list. You can disable collisions between two objects X and Y by invoking x.addToIgnoreList(y).

There’s no need to also invoke y.addToIgnoreList(x). That would be redundant.
Ignore lists are used internally by physics joints to disable collisions between the ends of a joint.

Using a dynamic filter

Libbulletjme invokes space.needsCollision() for each AABB overlap that isn’t suppressed by collision groups or ignore lists. The default implementation returns true, meaning "process this overlap".

You can dynamically filter AABB overlaps by overriding the needsCollision() method during the instantiation of the space. Return true for overlaps you want Bullet to handle. Return false for overlaps you want Bullet to ignore. needsCollision() can also be used to trigger arbitrary actions when 2 AABBs overlap.

needsCollision() is the most flexible mechanism for filtering collisions.

Access to manifolds and contact points

The physicsSpace.countManifolds() method returns the number of contact manifolds in the space. Each manifold has a native ID, as does each contact point.

  • The physicsSpace.listManifoldIds() method enumerates the IDs of all manifolds in the space.

  • To obtain detailed information about a specific manifold, use the methods in PersistentManifolds.

  • The PersistentManifolds.listPointIds() method enumerates the IDs of the contact points in a particular manifold.

  • To obtain detailed information about a specific contact point, use the methods in ManifoldPoints.

A manifold may persist for a while after the bodies no longer intersect. To confirm intersection, use ManifoldPoints.getDistance1() to get the separation distance. When the distance is positive, there’s no intersection.

ConveyorDemo is a SPORT app that implements conveyor belts using contact-point modification.

Custom contact handling

The physicsSpace.update() method has optional arguments to enable callbacks from Bullet during contact processing:

  • If the doStarted flag is true, then onContactStarted() will be invoked each time a manifold is created.

  • If the doProcessed flag is true, then onContactProcessed() will be invoked each time a contact point is processed.

  • If the doEnded flag is true, then onContactEnded() will be invoked each time a manifold is destroyed.

By default, doEnded, doProcessed, and doStarted are false and the callbacks are no-ops. To customize the callbacks, override the handlers during the instantiation of the PhysicsSpace.

A mechanism exists that implements contact handling using listeners. That mechanism is now deprecated.

Intersection tests

Pair test

The space.pairTest() method performs a pair test between 2 collision objects, returning true if they intersect.

Although a space is required, the objects needn’t be added to any space.

You can request a callback for each contact point that would be created if both collision objects were added to the space.

Ray test

The space.rayTest() method performs a ray test against a space, returning a list of objects in the space that intersect with the specified line segment.

Unlike a mathematical ray, the "ray" used in a ray test has both a starting point and an ending point.

To configure details of how ray tests are performed, use the space.setRayTestFlags() method.

Contact test

The contactTest() method performs a contact test against a space, returning the number of contact points that would be created if a specified collision object were added to the space.

To obtain more information about the contacts, you can request a callback for each point.

Contact testing doesn’t detect contacts involving soft bodies.

Sweep test

A sweep test combines features of a ray test and a contact test.

The sweepTest() method performs a sweep test against a space, returning a list of objects in the space that would intersect with a collision shape sweeping from one position to another.

The shape must be convex.

Summary

  • Overlaps, intersections, manifolds, and contact points are distinct concepts.

  • Libbulletjme provides filtering mechanisms to control which overlaps should be handled and which should be ignored.

  • Libbulletjme provides methods to enumerate overlaps, manifolds, and contact points.

  • You can trigger custom actions during each stage of collision processing.

  • Between simulation steps, you can perform pair tests, ray tests, contact tests, and sweep tests against a space.