---
id: advanced_collision_detection
title: Advanced collision-detection
sidebar_label: Advanced collision-detection
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

Collision-detection is a two-steps process. First the `BroadPhase` detects pairs of colliders
that are potentially in contact or intersecting. Second, the `NarrowPhase` processes all these pairs in order
to compute contacts points and generate [collision events](./advanced_collision_detection.mdx#collision-and-contact-force-events). Based on these points, the
constraints solver computes forces that may generate [contact force events](./advanced_collision_detection.mdx#collision-and-contact-force-events).

All the pairs detected by the broad-phase are stored into two graph structures:
- The [**contact graph**](./advanced_collision_detection.mdx#the-contact-graph) stores all the potential contact pairs (between two non-sensor colliders)
  as well as the contact points generated by the narrow-phase.
- The [**intersection graph**](./advanced_collision_detection.mdx#the-intersection-graph) stores all the potential intersection pairs (between a sensor collider
  and another collider) as well as the result of the boolean intersection test executed by the narrow-phase.

These two graphs are part of the `NarrowPhase` structure and are automatically updated by the `PhysicsPipeline`
or the `CollisionPipeline`. Each node of these graph contains a `ColliderHandle`
and there is one graph edge per pair detected by the broad-phase.

## Collision and contact force events
The narrow-phase can generate collision events between two colliders. Each collision event is given optional flags:
- `CollisionEventFlags::SENSOR` is set if at least one of the colliders involved in the collision is a sensor.
- `CollisionEventFlags::REMOVED` is set if a collision stopped because at least one of the colliders involved in the
  collision was removed from the physics scene.

In addition, after forces are computed by the constraints solver, contact force events may be generated between two
colliders subject to non-zero contact forces. Generally, the user isn’t interested in contact force events unless the
force magnitudes exceed some threshold. In order to skip low-force events, the engine will compute the sum of the
magnitude of all the contacts between the two colliders and only trigger a contact force event if that magnitude is
larger than the threshold set with <rapier>`ColliderBuilder::contact_force_event_threshold` or
`Collider::set_contact_force_event_threshold`</rapier><bevy>the `ContactForceEventThreshold` component</bevy>
(defaults to 0) for any of the two colliders with the `ActiveEvents::CONTACT_FORCE_EVENTS` flag enabled.

:::warning
Collision events (resp. contact force events) are only generated between two colliders if at least one of them has the
`ActiveEvents::COLLISION_EVENTS` flag (resp. `ActiveEvents::CONTACT_FORCE_EVENTS` flags) in its [active events](./colliders.mdx#active-events).
:::

<rapier>In order to handle these events, it is necessary to collect them using a structure implementing the `EventHandler` trait.
Because Rapier can be parallelized, this event handler must also implement `Send + Sync`.</rapier>

<rapier>

One such structure provided by Rapier is the `rapier::pipeline::ChannelEventCollector`. This event collector contains
channels from the [crossbeam crate](https://crates.io/crates/crossbeam). These channels will be populated with events
during each call to `PhysicsPipeline::step`:

```rust
<load path='/2d/rust/examples/rs_advanced_collision_detection2.rs' marker='Events' />
```

Note however that if you need to access the contact information at the exact time a contact event happens, you may
provide your own `EventHandler` implementation to access the contact pair given to `EventHandler::handle_collision_event`.
You may just query the `NarrowPhase` instead (after the timestep completed), but there are some cases when the contact
information is no longer available at the end of the timestep (e.g. when running multi-step CCD and the contact start
during one substep and steps at a substeps right after).

:::info
Collision events identify the involved colliders by their handle. It is possible to retrieve the handle of
the rigid-body a collider is attached to: `collider_set.get(collider_handle).unwrap().parent()`
:::

</rapier>
<bevy>

These events can be read using Bevy's event system with `EventReader`:

```rust
<load path='/2d/bevy/examples/advanced_collision_detection2.rs' marker='Events' />
```

</bevy>


## The contact graph
The contact graph can be read in order to determine whether two specific non-sensor colliders are in contact, or to determine
all the non-sensor colliders in contact with one particular non-sensor collider. Contact points and contact normals
will also be provided when a contact exists.

The contact geometry (contact points, contact normal, penetration depth, etc.) can be read from the contact
manifolds stored in a contact pair:
1. Each contact pair may contain multiple contact manifolds. Each contact manifold represents a set of contacts
   sharing the same contact normal.
2. Each contact manifold contains the list of **geometric contacts** detected by the narrow-phase.
3. Each contact manifold also contains a list of contacts that were processed by the constraints solver for force
   calculation (aka. the **solver contacts**). These **solver contacts** are a subset of the contacts detected by the narrow-phase,
   expressed in a way that is more efficient for the constraints solver to process. These solver contacts can be modified
   or deleted by the user using [contact modification](./advanced_collision_detection.mdx#contact-modification).

All the **geometric contact** data are expressed in the local-space of the colliders. The **solver contacts** hold one
anchor per body surface, expressed in the local-space of the body that surface belongs to (so they ride rigidly with
it); `ContactManifoldData::solver_contact_world_points` resolves them back to world-space through the bodies' current
poses. Inside a contact-modification hook they are world-space instead, since the hook runs before they are localized.

:::info
Because the solver contacts can be modified by the user, they are transients by nature:
they are recomputed  at each frame from the geometric contacts. Because of their transient nature, the constraint solver will
store the forces it computes inside of the geometric contacts `TrackedContact::data::impulse` field instead of the solver
contacts themselves.
:::

Keep in mind that the contact graph contains one graph edge per pair detected by the broad-phase. So
the fact that a contact pair can be found in the graph doesn't mean that the corresponding colliders are
__actually__ in contact (they may just be very close to one another, without touching). It is necessary
to check either:
- the`ContactPair::has_any_active_contact` if you need to know if there exist at least one solver contact
  between the colliders.
- the length of `ContactManifold:points` for each manifold in `ContactPair::manifolds` to determine
  if the colliders are really geometrically touching (independently from contact-modification).

:::info
There will always be only up to one contact manifold between two colliders with convex primitive shapes. If one
collider has a shape composed of several pieces (trimesh, polyline, heightfield, or compound shape) then there
will be multiple contact manifolds, one for each piece that may result in an actual contact.
:::

<rapier>

```rust
<load path='/2d/rust/examples/rs_advanced_collision_detection2.rs' marker='ContactGraph1' />
```
```rust
<load path='/2d/rust/examples/rs_advanced_collision_detection2.rs' marker='ContactGraph2' />
```

</rapier>
<bevy>

```rust
<load path='/2d/bevy/examples/advanced_collision_detection2.rs' marker='ContactGraph1' />
```
```rust
<load path='/2d/bevy/examples/advanced_collision_detection2.rs' marker='ContactGraph2' />
```

</bevy>

Finally, keep in mind that the contacts and contact manifolds field names frequently end with a digit `1` or `2`.
For example `contact_pair.manifolds[0].local_n1` and `contact_pair.manifolds[0].local_n2`. Fields ending with
the digit `1` relate to the collider identified by `contact_pair.collider1`. Fields ending with the digit `2`
relate to the collider identified by `contact_pair.collider2`.

In other words `local_n1` is the contact normal expressed in the local space of the collider `collider_pair.collider1`,
it points towards the exterior of the shape of `collider_pair.collider1`. On the other hand, `local_n2` is expressed in
the local space of the collider `collider_pair.collider2` and points towards the exterior of the shape of
`collider_pair.collider2`.

:::warning
The contact pair returned by `narrow_phase.contact_pair(handle1, handle2)` does not necessarily
have `contact_pair.collider1 == handle1 && contact_pair.collider2 == handle2`. It could be swapped:
`contact_pair.collider1 == handle2 && contact_pair.collider2 == handle1`.

So keep that in mind when reading the contact information because it's `contact_pair.collider1` and `contact_pair.collider2`
that determine to what collider the digits `1` and `2` relate in the contacts and contact manifolds fields.
:::


## The intersection graph
The intersection graph can be read in order to determine whether two specific colliders (assuming at least one of them is
a sensor) are intersecting, or to determine all the colliders intersecting one particular collider (assuming at least one
collider of each pair is a sensor). The intersection graph contains one graph edge for each pair of colliders such that:
1. At least one of the collider is a sensor.
2. And they are close enough so the broad-phase considers they have a chance to be intersecting.

Each such edge contains one boolean indicating if the colliders are actually intersecting or not:

<rapier>

```rust
<load path='/2d/rust/examples/rs_advanced_collision_detection2.rs' marker='IntersectionGraph1' />
```
```rust
<load path='/2d/rust/examples/rs_advanced_collision_detection2.rs' marker='IntersectionGraph2' />
```

</rapier>
<bevy>


```rust
<load path='/2d/bevy/examples/advanced_collision_detection2.rs' marker='IntersectionGraph1' />
```
```rust
<load path='/2d/bevy/examples/advanced_collision_detection2.rs' marker='IntersectionGraph2' />
```

</bevy>

:::warning
Keep in mind that intersection tests are performed between two colliders only if at least one of the colliders
is a sensor. If they are both non-sensor colliders then they will be involved in the [contact graph](./advanced_collision_detection.mdx#the-contact-graph)
instead of the intersection graph.
:::

## Physics hooks
Physics hooks are user-defined callbacks used to change the behavior of the physics simulation. In particular,
they can be used to [filter contacts](./advanced_collision_detection.mdx#contact-and-intersection-filtering) (in a more flexible way than
[collision groups and solver groups](./colliders.mdx#collision-groups-and-solver-groups)) and to
[modify contacts](./advanced_collision_detection.mdx#contact-modification) before they are processed by the constraints solver.

<rapier>

Physics hooks are given as an argument of the `PhysicsPipeline::step` and `CollisionPipeline::step` methods.
All physics hooks are grouped into the `PhysicsHooks` trait that defines one method per kind of hook.

:::info
If no physics hooks are needed by your simulation, it is possible to use `&()` as the physics hooks argument. `()` is
a physics hooks that does nothing particular.
:::

</rapier>
<bevy>

Physics hooks are given as a type argument to `RapierPhysicsPlugin`. The hooks type must implement `BevyPhysicsHooks`
trait. The trait requires `SystemParam` trait to also be implemented which is useful for example to access components
attached to the entities to guide contact filtering. For physics hooks to work, the following steps must be taken:
- The `RapierPhysicsPlugin` must be parametrized by the custom physics hooks type
- The custom physics hooks must implement the `BevyPhysicsHooks` trait
- The custom physics hooks must implement `SystemParam` trait for example using `derive` macro

:::note
If you don't need any physics hooks, `NoUserData` should be passed as a plugin type parameter:
`RapierPhysicsPlugin::<NoUserData>::default()`.
:::


</bevy>

### Contact and intersection filtering
Sometimes, [collision groups and solver groups](./colliders.mdx#collision-groups-and-solver-groups) are not flexible enough
to achieve the desired behavior. In that case, the contact filtering hooks let you apply custom rules to filter contact
pairs and intersection pairs:
- For each potential contact pair (between two non-sensor colliders) detected by the broad-phase, if at least one
  of the colliders involved in the pair has the bit `ActiveHooks::FILTER_CONTACT_PAIRS` enabled in its
  [active hooks](./colliders.mdx#active-hooks), then `PhysicsHooks::filter_contact_pair` will be called. If this filter
  returns `None` then no contact computation will happen for this pair of colliders. If it returns `Some` then the
  narrow-phase will compute contact points.
- For each potential intersection pair (between a sensor colliders and another collider) detected by the broad-phase, if
  at least one of the colliders involved in the pair has the bit `ActiveHooks::FILTER_INTERSECTION_PAIR` enabled
  in its [active hooks](./colliders.mdx#active-hooks), then `PhysicsHooks::filter_intersection_pair` will be called. If this
  filter returns `false` then no intersection computation will happen for this pair of colliders. If it returns `true`
  then the narrow-phase will test whether or not they are intersecting.

When `PhysicsHooks::filter_contact_pair` returns `Some(flags)` it needs to provide a set of solver flags for this contact
pair. These solver flags indicate what happen with the contacts of this contact pair afterwards:
- If the returned `Some(flags)` contains the `SolverFlags::COMPUTE_IMPULSES` bit, then the constraints solver will
  compute forces for these contacts. If this bit is not included in the returned flags, then no contact force will
  be computed for this pair of colliders.

:::note
Right now there is no solver flags other than `SolverFlags::COMPUTE_IMPULSES`. Other flags may be added in the future.
:::

<rapier>

```rust
<load path='/2d/rust/examples/rs_advanced_collision_detection2.rs' marker='PhysicsHooks' />
```

</rapier>
<bevy>

```rust
<load path='/2d/bevy/examples/physics_hooks.rs' marker='PhysicsHooks' />
```

</bevy>

### Contact modification
It is possible to modify contacts after they have been computed by the narrow-phase. Contact-modification can have
multiple advanced usages, for example:
- The simulation of **conveyor belts** by modifying the `tangent_velocity` of solver contacts.
- The simulation of **one-way-platforms** by deleting some contacts depending on the contact normal.
- The simulation of colliders whose **friction** or **restitution** depends on where they are touched,
  by setting the coefficients from the contact points' location.

The `PhysicsHooks::modify_solver_contacts` methods is called on each contact manifold between two colliders where at
least one of them has the `ActiveHooks::MODIFY_SOLVER_CONTACTS` flag enabled in its
[active hooks](./colliders.mdx#active-hooks).

:::warning
Contact modification can be used to remove some (or all) solver contacts from a contact manifold. However, it cannot
be used to add new contacts manually. If this is something that could useful to you, please consider
[opening an issue](https://github.com/dimforge/rapier/issues/new) to let us know about your use-case so we can see if this
is worth adding.
:::

Contact-modification lets you change most characteristics of a contact: the contact normal, the contact points and
their penetration depth, and the tangent velocity. The friction and restitution coefficients are combined once per
manifold, so they are set for the whole manifold (`context.friction` / `context.restitution`) rather than per contact.
None of these modifications are persistent (they
are overwritten during the next timestep). There is one exception though: you can modify a `user_data` associated to
each `ContactManifold`. This `user_data` will persist throughout timesteps as long as the `ContactManifold` remains alive
(i.e. as long as some contacts exist between the touching parts of the colliders shapes). This can be useful
to apply modification rules that depend on previous states of the contact (like whether or not this contact manifold
existed during previous timesteps).

<rapier>

```rust
<load path='/2d/rust/examples/rs_advanced_collision_detection2.rs' marker='ContactModification' />
```

</rapier>
<bevy>

```rust
<load path='/2d/bevy/examples/contact_modification.rs' marker='ContactModification' />
```

</bevy>

## Continuous Collision Detection
Continuous Collision Detection (CCD) is used to make sure that fast-moving objects don't miss any contacts (a problem
usually called _tunneling_). See the [rigid-body CCD section](./rigid_bodies.mdx#continuous-collision-detection) for details.
