Skip to main content

collider_collision_groups

The most efficient way of preventing some pairs of colliders from interacting with each other is to use collision groups or solver groups. Each collider is given:

  • A collision_groups for filtering what pair of colliders should have their contacts (or intersection test if at least one of the colliders is a sensor) computed by the narrow-phase. This filtering happens right after the broad-phase, at the beginning of the narrow phase.
  • A solver_groups for filtering what pair of colliders should have their contact forces computed. This filtering happens at the end of the narrow-phase, before the constraints solver.

In other words, the solver_groups is here to prevent contact forces from being computed between some colliders, whereas the collision_groups will also prevent the contact themselves (and contact events) from being computed. The collision_groups should be preferred most of the time because it skips more computations. The solver_groups is only useful if you really want the contact information to be computed but not the forces, for example so that you can apply your own forces based on these contacts.

A collision group or solver group is described as a pair of bit masks:

  • The groups membership indicates what groups the collider is part of (one bit per group).
  • The groups filter indicates what groups the collider can interact with (one bit per group).

The collision groups and solver groups (the collisionGroups and solverGroups fields of the collider description) are given by a R3InteractionGroups structure containing both bit masks, as memberships and filter, as well as a test_mode explained at the end of this section.

info

Because the memberships and filter bit masks are uint32_t there is a total of 32 groups. By default all bits are set to 1: the collider is part of every group, and can interact with every group.

For example, let's say we want our collider A to be part of the groups [0, 2, 3] and to be able to interact with the groups [2], then its groups membership is 0b1101 = 0xD and its groups filter is 0b0100 = 0x4. The collision groups and solver groups of a collider can be set during or after its creation:

/* Set the collision groups and solver groups when the collider is created. */
R2ColliderDesc collider = r2BallColliderDesc(0.5);
collider.collisionGroups = (R2InteractionGroups){
.memberships = (1u << 0) | (1u << 2) | (1u << 3), // Groups 0, 2, and 3.
.filter = 1u << 2, // Group 2.
.test_mode = R2_GROUPS_AND,
};
collider.solverGroups = (R2InteractionGroups){
.memberships = (1u << 0) | (1u << 1), // Groups 0 and 1.
.filter = (1u << 0) | (1u << 1) | (1u << 3), // Groups 0, 1, and 3.
.test_mode = R2_GROUPS_AND,
};
/* Set the collision groups and solver groups after the collider creation. */
R2InteractionGroups collision_groups = {
.memberships = (1u << 0) | (1u << 2) | (1u << 3), // Groups 0, 2, and 3.
.filter = 1u << 2, // Group 2.
.test_mode = R2_GROUPS_AND,
};
R2InteractionGroups solver_groups = {
.memberships = (1u << 0) | (1u << 1), // Groups 0 and 1.
.filter = (1u << 0) | (1u << 1) | (1u << 3), // Groups 0, 1, and 3.
.test_mode = R2_GROUPS_AND,
};
r2Collider_SetCollisionGroups(collider_handle, collision_groups);
r2Collider_SetSolverGroups(collider_handle, solver_groups);
assert(r2Collider_CollisionGroups(collider_handle).memberships == collision_groups.memberships);
assert(r2Collider_SolverGroups(collider_handle).filter == solver_groups.filter);

After the broad-phase detects that two colliders A and B may start being in contact, the narrow-phase will check the collision groups of both colliders to see if it needs to compute contacts. The check operates as follows:

  • If the collider A is not member of any collision group in the filter of B, then no contact is computed.
  • If the collider B is not member of any collision group in the filter of A, then no contact is computed.
  • The exact bit-wise check is the following:
   (r3Collider_CollisionGroups(a).memberships & r3Collider_CollisionGroups(b).filter) != 0
&& (r3Collider_CollisionGroups(b).memberships & r3Collider_CollisionGroups(a).filter) != 0

If this test succeeds, then the narrow-phase will compute the contacts. Then it will check the solver groups of both colliders, using the same kind of tests as described before but using the solver_groups instead of collision_groups. If the test succeeds then the constraints solver will compute forces for these contacts. Otherwise, it won't.

info

This is the behavior of the default R3_GROUPS_AND test mode (the test_mode field of R3InteractionGroups). If both colliders use the R3_GROUPS_OR test mode, then satisfying only one of these two conditions is enough for the contacts (or forces) to be computed.