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_groupsfor 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_groupsfor 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.
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
Ais not member of any collision group in the filter ofB, then no contact is computed. - If the collider
Bis not member of any collision group in the filter ofA, 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.
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.