Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Objective
#385 added speculative collision, a form of Continuous Collision Detection (CCD) with the goal of preventing tunneling. However, it isn't perfect; speculative collision can sometimes cause ghost collisions, and it can miss collisions against objects spinning at very high speeds.
Another form of CCD is swept CCD, which sweeps colliders from their previous positions to the current ones, and moves the bodies to the time of impact if a hit was found. This can be more reliable than speculative collision, and can act as a sort of safety net when you want to ensure that an object has no tunneling, at the cost of being more expensive and causing "time loss" where bodies appear to stop momentarily as they are brought back in time.
Both forms of CCD are valuable and should exist. They can also be used together to complement each other!
Solution
Add a
CcdPlugin
that performs sweep-based CCD for rigid bodies that have theSweptCcd
component.Two sweep modes are supported:
SweptCcd::mode
isSweepMode::Linear
, only translational motion is considered.SweptCcd::mode
isSweepMode::NonLinear
, both translational and rotational motion are considered. This is more expensive.By default, the mode is
SweepMode::NonLinear
, but it can be specified using associated constantsSweptCcd::Linear
orSweptCcd::NonLinear
, or by using theSweptCcd::new_with_mode
constructor.It may not be desirable to have CCD enabled for all collisions. To enable it based on the relative velocities of the bodies involved, velocity thresholds can be set:
Additionally, swept CCD can be disabled for collisions against dynamic bodies:
Below you can see the new
ccd
example and the different forms of CCD in action!2024-07-02.02-31-48.mp4
As you can see, all the different modes and combinations behave differently, and have their own unique characteristics and trade-offs. In this spinning example, sweep-based CCD clearly has time loss, especially with speculative collision disabled. Non-linear swept CCD is also the most reliable however, as it doesn't let any of the projectiles tunnel through. Linear swept CCD on the other hand struggles a lot in this case since it doesn't take rotational motion into account.
Of course, this is a very extreme and relatively niche example. For most objects in most games, speculative collision should be enough, and swept CCD can be used as a safety net when it isn't.
Implementation
The implementation works as follows:
SweptCcd
in anAabbIntersections
component.solve_swept_ccd
, iterate through the AABB intersections for each entity withSweptCcd
, and perform shape casts to find the minimum time of impact.SweptCcd::mode
isSweepMode::Linear
, only translational motion is considered.SweptCcd::mode
isSweepMode::NonLinear
, both translational and rotational motion are considered. This is more expensive.A number of physics engines were used as inspiration for the implementation and terminology, primarily Box2D V3, Bepu, and Jolt.
Unlike Rapier, I did not implement substepping for the time of impact solver, because it is more expensive and complex, and likely much more difficult to parallelize in the future. I believe Box2D V3 is opting for a similar approach for similar reasons.