Add swept SDF collision sequence error function (anti-tunneling) (#1526)#1526
Open
cdtwigg wants to merge 1 commit into
Open
Add swept SDF collision sequence error function (anti-tunneling) (#1526)#1526cdtwigg wants to merge 1 commit into
cdtwigg wants to merge 1 commit into
Conversation
Contributor
|
@cdtwigg has exported this pull request. If you are a Meta employee, you can view the originating Diff in D108807348. |
meta-codesync Bot
pushed a commit
that referenced
this pull request
Jun 17, 2026
Summary: Add `SDFCollisionSequenceErrorFunctionT`, a two-frame `SequenceErrorFunctionT` that penalizes a vertex sweeping through an SDF collider between consecutive frames. The single-frame `SDFCollisionErrorFunctionT` only sees penetration at the sampled poses, so a vertex moving fast enough to pass entirely through a thin collider (a finger, say) in one timestep is never penalized — it tunnels. This closes that gap for the sequence solver, which is used to post-process existing motion. How it works: - For each participating vertex, the segment connecting its position at frame t and t+1 is swept against each collider in the collider's local SDF frame: each endpoint is mapped through its own frame's world-to-collider transform and the two local positions are interpolated linearly. This captures the relative motion when both vertex and collider are joint-driven, keeps the interpolation exactly differentiable (no slerp-derivative approximation), and makes the sphere-trace that locates surface crossings exactly conservative (distances and steps are in the same local units, so a thin feature can't be stepped over). - The penalty is `w * phiMax^2` per penetrating sub-interval, where `phiMax` is the greatest penetration depth reached along the sweep. It is a max, not an integral, so it depends only on how deep the pass-through gets, never on how long the segment stays inside (no degenerate "stretch the trajectory to dilute the penalty" direction). The deepest point is located exactly by bisecting `d'(s) = 0`; because it is a true interior extremum, the envelope theorem makes the gradient independent of how the deepest point drifts with the parameters, so it reduces to the single-frame contact gradient evaluated there, split across the two frames by the interpolation weights `(1 - s*)` and `s*`. One residual per interval; gradient and Jacobian both finite-difference clean. - Only sub-intervals bounded by two real surface crossings (entry and exit) are penalized, targeting the pure pass-through case and leaving at-frame penetration to the per-frame error function. - Derivatives reuse the shared `detail_sdf_collision` chain-rule helpers from the previous diff, evaluated against both frames' skeleton states. The local SDF gradient is mapped to world space including the world-to-collider scale factor, which the derivatives require whenever the collider's joint carries a non-unit scale. The penetration normal is treated as frozen per evaluation (the standard Gauss-Newton contact linearization), so no SDF second derivatives are needed — only transform derivatives, which the shared helpers already provide. Known limitation / follow-up: a vertex passing exactly through a collider's medial axis (dead-center through the axis of a thin tube, or perpendicular through a thin sheet) lands on a degenerate point where the SDF normal is undefined and the depth has a non-smooth maximum, so the gradient there is ~0 and gives no signal. This is a measure-zero case for convex colliders (any off-axis pass resolves correctly by deflection); a retract-along-the-entry-normal fallback for it is a planned follow-up. There is also no broadphase culling yet (every participating vertex is swept against every collider) and no pymomentum binding (the single-frame function has one). Reviewed By: yutingye Differential Revision: D108807348
e5ae335 to
1316202
Compare
Summary: Add `SDFCollisionSequenceErrorFunctionT`, a two-frame `SequenceErrorFunctionT` that penalizes a vertex sweeping through an SDF collider between consecutive frames. The single-frame `SDFCollisionErrorFunctionT` only sees penetration at the sampled poses, so a vertex moving fast enough to pass entirely through a thin collider (a finger, say) in one timestep is never penalized — it tunnels. This closes that gap for the sequence solver, which is used to post-process existing motion. How it works: - For each participating vertex, the segment connecting its position at frame t and t+1 is swept against each collider in the collider's local SDF frame: each endpoint is mapped through its own frame's world-to-collider transform and the two local positions are interpolated linearly. This captures the relative motion when both vertex and collider are joint-driven, keeps the interpolation exactly differentiable (no slerp-derivative approximation), and makes the sphere-trace that locates surface crossings exactly conservative (distances and steps are in the same local units, so a thin feature can't be stepped over). - The penalty is `w * phiMax^2` per penetrating sub-interval, where `phiMax` is the greatest penetration depth reached along the sweep. It is a max, not an integral, so it depends only on how deep the pass-through gets, never on how long the segment stays inside (no degenerate "stretch the trajectory to dilute the penalty" direction). The deepest point is located exactly by bisecting `d'(s) = 0`; because it is a true interior extremum, the envelope theorem makes the gradient independent of how the deepest point drifts with the parameters, so it reduces to the single-frame contact gradient evaluated there, split across the two frames by the interpolation weights `(1 - s*)` and `s*`. One residual per interval; gradient and Jacobian both finite-difference clean. - Only sub-intervals bounded by two real surface crossings (entry and exit) are penalized, targeting the pure pass-through case and leaving at-frame penetration to the per-frame error function. - Derivatives reuse the shared `detail_sdf_collision` chain-rule helpers from the previous diff, evaluated against both frames' skeleton states. The local SDF gradient is mapped to world space including the world-to-collider scale factor, which the derivatives require whenever the collider's joint carries a non-unit scale. The penetration normal is treated as frozen per evaluation (the standard Gauss-Newton contact linearization), so no SDF second derivatives are needed — only transform derivatives, which the shared helpers already provide. Known limitation / follow-up: a vertex passing exactly through a collider's medial axis (dead-center through the axis of a thin tube, or perpendicular through a thin sheet) lands on a degenerate point where the SDF normal is undefined and the depth has a non-smooth maximum, so the gradient there is ~0 and gives no signal. This is a measure-zero case for convex colliders (any off-axis pass resolves correctly by deflection); a retract-along-the-entry-normal fallback for it is a planned follow-up. There is also no broadphase culling yet (every participating vertex is swept against every collider) and no pymomentum binding (the single-frame function has one). Reviewed By: yutingye Differential Revision: D108807348
1316202 to
8be474e
Compare
meta-codesync Bot
pushed a commit
that referenced
this pull request
Jun 17, 2026
Summary: Add `SDFCollisionSequenceErrorFunctionT`, a two-frame `SequenceErrorFunctionT` that penalizes a vertex sweeping through an SDF collider between consecutive frames. The single-frame `SDFCollisionErrorFunctionT` only sees penetration at the sampled poses, so a vertex moving fast enough to pass entirely through a thin collider (a finger, say) in one timestep is never penalized — it tunnels. This closes that gap for the sequence solver, which is used to post-process existing motion. How it works: - For each participating vertex, the segment connecting its position at frame t and t+1 is swept against each collider in the collider's local SDF frame: each endpoint is mapped through its own frame's world-to-collider transform and the two local positions are interpolated linearly. This captures the relative motion when both vertex and collider are joint-driven, keeps the interpolation exactly differentiable (no slerp-derivative approximation), and makes the sphere-trace that locates surface crossings exactly conservative (distances and steps are in the same local units, so a thin feature can't be stepped over). - The penalty is `w * phiMax^2` per penetrating sub-interval, where `phiMax` is the greatest penetration depth reached along the sweep. It is a max, not an integral, so it depends only on how deep the pass-through gets, never on how long the segment stays inside (no degenerate "stretch the trajectory to dilute the penalty" direction). The deepest point is located exactly by bisecting `d'(s) = 0`; because it is a true interior extremum, the envelope theorem makes the gradient independent of how the deepest point drifts with the parameters, so it reduces to the single-frame contact gradient evaluated there, split across the two frames by the interpolation weights `(1 - s*)` and `s*`. One residual per interval; gradient and Jacobian both finite-difference clean. - Only sub-intervals bounded by two real surface crossings (entry and exit) are penalized, targeting the pure pass-through case and leaving at-frame penetration to the per-frame error function. - Derivatives reuse the shared `detail_sdf_collision` chain-rule helpers from the previous diff, evaluated against both frames' skeleton states. The local SDF gradient is mapped to world space including the world-to-collider scale factor, which the derivatives require whenever the collider's joint carries a non-unit scale. The penetration normal is treated as frozen per evaluation (the standard Gauss-Newton contact linearization), so no SDF second derivatives are needed — only transform derivatives, which the shared helpers already provide. Known limitation / follow-up: a vertex passing exactly through a collider's medial axis (dead-center through the axis of a thin tube, or perpendicular through a thin sheet) lands on a degenerate point where the SDF normal is undefined and the depth has a non-smooth maximum, so the gradient there is ~0 and gives no signal. This is a measure-zero case for convex colliders (any off-axis pass resolves correctly by deflection); a retract-along-the-entry-normal fallback for it is a planned follow-up. There is also no broadphase culling yet (every participating vertex is swept against every collider) and no pymomentum binding (the single-frame function has one). Reviewed By: yutingye Differential Revision: D108807348
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.
Summary:
Add
SDFCollisionSequenceErrorFunctionT, a two-frameSequenceErrorFunctionTthat penalizes a vertex sweeping through an SDF collider between consecutive frames. The single-frameSDFCollisionErrorFunctionTonly sees penetration at the sampled poses, so a vertex moving fast enough to pass entirely through a thin collider (a finger, say) in one timestep is never penalized — it tunnels. This closes that gap for the sequence solver, which is used to post-process existing motion.How it works:
w * phiMax^2per penetrating sub-interval, wherephiMaxis the greatest penetration depth reached along the sweep. It is a max, not an integral, so it depends only on how deep the pass-through gets, never on how long the segment stays inside (no degenerate "stretch the trajectory to dilute the penalty" direction). The deepest point is located exactly by bisectingd'(s) = 0; because it is a true interior extremum, the envelope theorem makes the gradient independent of how the deepest point drifts with the parameters, so it reduces to the single-frame contact gradient evaluated there, split across the two frames by the interpolation weights(1 - s*)ands*. One residual per interval; gradient and Jacobian both finite-difference clean.detail_sdf_collisionchain-rule helpers from the previous diff, evaluated against both frames' skeleton states. The local SDF gradient is mapped to world space including the world-to-collider scale factor, which the derivatives require whenever the collider's joint carries a non-unit scale.The penetration normal is treated as frozen per evaluation (the standard Gauss-Newton contact linearization), so no SDF second derivatives are needed — only transform derivatives, which the shared helpers already provide.
Known limitation / follow-up: a vertex passing exactly through a collider's medial axis (dead-center through the axis of a thin tube, or perpendicular through a thin sheet) lands on a degenerate point where the SDF normal is undefined and the depth has a non-smooth maximum, so the gradient there is ~0 and gives no signal. This is a measure-zero case for convex colliders (any off-axis pass resolves correctly by deflection); a retract-along-the-entry-normal fallback for it is a planned follow-up. There is also no broadphase culling yet (every participating vertex is swept against every collider) and no pymomentum binding (the single-frame function has one).
Reviewed By: yutingye
Differential Revision: D108807348