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 implement contact response, including friction and restitution.

Minie 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 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 usually performed between simulation steps. They are useful (for instance) when you want to add an 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 directly 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 simple application 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 (in yellow) has a spherical shape, but its AABB (in white) is box-shaped.

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

  3. The ghost’s overlap count (displayed at the bottom of the window) is initially one, due to its overlap with the ground plane.

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

  5. As soon as the character’s AABB touches the ghost’s AABB, the count increases to 2, even though their collision shapes haven’t intersected yet.

  6. Press Space bar to jump.

  7. The character can jump high enough to leave the ghost’s AABB, at which time the count will momentarily return to 1.

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

The alternative to creating a ghost directly is to add a GhostControl to the scene graph.

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. Minie 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

For each collision group in a space, you can register a collision-group listener. Minie invokes the collision-group listeners for each AABB overlap that isn’t suppressed by collision groups or ignore lists.

You can dynamically filter AABB overlaps by registering a listener that returns true for overlaps that may cause collisions and false for those that should never cause collisions.

Collision-group listeners are 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.

Collision/contact listeners

For each physics space, you can register 3 kinds of collision/contact listeners:

registration method Listeners are invoked during…​ for every…​

addCollisionListener()

physicsSpace.distributeEvents()

contact created since the last distributeEvents() call.

addOngoingCollisionListener()

physicsSpace.distributeEvents()

contact point processed since the last distributeEvents() call.

addContactListener()

physicsSpace.update()

contact created or removed and every contact point that is processed.

BulletAppState invokes distributeEvents() during each update.

Ragdoll listeners

For each DynamicAnimControl, you can register collision listeners that will be invoked after each contact is created, provided:

  1. the contact involves the ragdoll and

  2. the applied impulse exceeds a configurable threshold.

Intersection tests

Ray test

The space.rayTest() method performs 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.

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

  • Minie 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 ray tests, contact tests, and sweep tests against a space.