fix(ccd): honor filter_contact_pair PhysicsHook during CCD (closes #754)#929
Merged
sebcrozet merged 2 commits intodimforge:masterfrom Apr 15, 2026
Merged
fix(ccd): honor filter_contact_pair PhysicsHook during CCD (closes #754)#929sebcrozet merged 2 commits intodimforge:masterfrom
sebcrozet merged 2 commits intodimforge:masterfrom
Conversation
Closes dimforge#754. The narrow phase already consulted the user's `filter_contact_pair` hook when deciding whether to compute contacts for a pair. CCD's `find_first_impact` and `predict_impacts_at_next_positions` did not, so fast-moving CCD-enabled bodies still got motion-clamped by pairs the user had filtered out. This thread `hooks: &dyn PhysicsHooks` through both CCD entry points and calls the filter at each pair-evaluation site (one in `find_first_impact`, two in `predict_impacts_at_next_positions` — the first-sweep loop and the resweep loop). The shared logic lives in a private `pair_filtered_out_by_hooks` helper in `ccd_solver.rs` that mirrors narrow-phase semantics exactly. Signature change: `CCDSolver::find_first_impact` and `CCDSolver::predict_impacts_at_next_positions` take an extra `hooks: &dyn PhysicsHooks` argument. `PhysicsPipeline::step` callers are unaffected; only code calling the CCD solver directly needs to update. Regression test added in `pipeline::physics_pipeline::test` that reproduces the bug: a 200 m/s CCD body rejected from a pair via `filter_contact_pair` passes through instead of clamping.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Member
|
Looks good, thanks! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
What
Makes Continuous Collision Detection consult the user's
PhysicsHooks::filter_contact_pairhook, matching narrow-phase semantics. Previously, CCD would clamp a fast-moving body's motion at a predicted impact with a pair the user had filtered out, leading to the bug described in #754.Why
Per the issue, "filtering in rapier is done in narrow phase only, for contacts and intersections (bodies and areas). The problem is in case of CCD we don't do any of these filterings." When a user enables CCD on an object and also installs a
filter_contact_pairhook to suppress certain collisions, the hook is bypassed during CCD's time-of-impact sweeps — so the fast body still gets motion-clamped on a pair the user told the engine to ignore.How
pair_filtered_out_by_hooksinsrc/dynamics/ccd/ccd_solver.rsthat mirrors the filter call inNarrowPhase::compute_contacts(checksActiveHooks::FILTER_CONTACT_PAIRSon either collider, builds aPairFilterContext, returnstrueonNone).find_first_impact(substep splitting)predict_impacts_at_next_positionsfirst-sweep loop (initial TOI collection)predict_impacts_at_next_positionsresweep loop (after freezing bodies)hooks: &dyn PhysicsHooksis threaded through the two publicCCDSolvermethods and throughPhysicsPipeline::run_ccd_motion_clamping.Breaking change
CCDSolver::find_first_impactandCCDSolver::predict_impacts_at_next_positionsnow take an extrahooks: &dyn PhysicsHooksargument.PhysicsPipeline::stepcallers are unaffected — only code that drives the CCD solver directly (uncommon) needs to pass the hooks argument.If you'd prefer a non-breaking additive approach (e.g., keep the current signatures and add
*_with_hooksvariants that take the extra param), I'm happy to restructure — I went with the breaking approach because rapier already makes breaking changes between minor versions and it keeps the surface clean.Test
Added
pipeline::physics_pipeline::test::ccd_respects_filter_contact_pair_hook(3D) that:x > 10rather than clamping near the stationary body (which happens without the fix atx ≈ -0.77).Empirically verified on a downstream project that the same scenario fails before this patch and passes after.
CHANGELOG
Added an
Unreleasedsection with the fix and the breaking-change note.Notes for review
filter_contact_pairfor sensor pairs too (and usessolver_flagsto decide what to do downstream). CCD's sweep sites skip sensors before calling this helper, which is intentional — CCD only resolves contact TOIs, and sensor intersection events are reported elsewhere. Called out in the helper's doc comment.filter_contact_paircalled up to 3× per step now (once per CCD sweep + narrow phase). Narrow phase already calls per-pair per-step; I don't expect the CCD sweeps to dominate in practice since CCD is only engaged for fast bodies.