Skip to content

Fix scale-dependent MPR contacts on large mesh triangles - #3766

Open
LuyiLi wants to merge 2 commits into
newton-physics:mainfrom
LuyiLi:fix/scale-bounded-triangle-mpr-seed
Open

Fix scale-dependent MPR contacts on large mesh triangles#3766
LuyiLi wants to merge 2 commits into
newton-physics:mainfrom
LuyiLi:fix/scale-bounded-triangle-mpr-seed

Conversation

@LuyiLi

@LuyiLi LuyiLi commented Aug 2, 2026

Copy link
Copy Markdown

Description

Problem

In some poses, MPR turns a local contact between a small cylinder and a large triangle into a false, tens-of-metres penetration with witness points far from the cylinder. In the deterministic reproduction, the correct penetration is 0.061719 m, but Newton ee84505a returns 58.826744 m; only the overlap boolean is correct.

The vulnerable case is near-coplanar: the convex center is close to the triangle plane, while its projection lies inside a large face but far from the triangle centroid. The existing initialization shifts that projection toward the centroid by 1% of their separation. Here that adds 0.474106 m tangentially against only 0.000361 m normally, making the initial MPR direction nearly tangent to the face. An instrumented trace in #3773 shows the resulting pose-sensitive portal branch and nonlocal witness reconstruction.

Changes

This PR preserves the shared-edge manifold intent of #2276 without letting the initialization scale with triangle size:

  • For projections in the closed face region, construct the base Minkowski center offset directly as -d * n from signed plane distance d and face normal n. This avoids a false tangent residual from subtracting large nearby float32 positions.
  • For |d| > 0, bound the centroid-directed tangent bias to 0.01 * min(|G-P|, |d|). Its tangent/normal ratio is therefore at most 0.01, independent of triangle size.
  • For exact d=0, use a triangle-specific face-normal fallback with the same centroid direction instead of the generic world-axis probe.
  • Preserve the real tangent distance outside the face and the existing degenerate-triangle behavior.
  • Add direct regressions for the reported pose, exact coplanarity, and shared-edge witnesses both above and on the plane.

Simply removing the centroid bias is not sufficient: it fixes the large-face case but makes adjacent triangles produce seam-biased witnesses. The bounded rule and triangle-specific fallback preserve those distinct witnesses, including at d=0.

Closes #3773. Related: #2276 and isaac-sim/IsaacLab#5071.

Checklist

  • New or existing tests cover these changes
  • The documentation is up to date with these changes (no public API or workflow change)
  • CHANGELOG.md has been updated (user-facing collision fix)

Test plan

Validated with Warp 1.16.0.dev20260716, the version locked by base commit ee84505a, and Python 3.12.3:

python -m unittest -v newton.tests.test_mpr
python -m unittest -v newton.tests.test_gjk
python -m unittest -v \
  newton.tests.test_narrow_phase.TestExtremeMeshTriangles.test_huge_triangle_center \
  newton.tests.test_narrow_phase.TestExtremeMeshTriangles.test_huge_triangle_near_edge \
  newton.tests.test_narrow_phase.TestExtremeMeshTriangles.test_huge_triangle_near_vertex \
  newton.tests.test_narrow_phase.TestExtremeMeshTriangles.test_shared_edge_flat
pre-commit run --files newton/_src/geometry/mpr.py newton/tests/test_mpr.py CHANGELOG.md

All listed tests and hooks pass. Additional deterministic validation covered:

  • 1001 heights from 0 to 2 mm in 2 μm steps, with no invalid depth, normal, or witness result;
  • triangle scales from 0.005x to 10x, with penetration within 2.9e-5 relative error and normal.z >= 0.99999994;
  • the exact reported input: 58.826744 m on ee84505a, 0.061719764 m with this PR.

Bug fix

Steps to reproduce:

  1. Run the standalone CPU reproduction in [BUG] MPR can return metre-scale penetration and nonlocal witnesses for small convex shapes on large triangles #3773 on Newton ee84505a.
  2. Observe overlap=True, penetration 58.826744 m, a mostly tangential normal, and nonlocal witnesses.
  3. Compare with the analytic cylinder-plane penetration 0.061719150 m.
  4. Run the same case with this PR and observe local witnesses, a face-normal contact, and penetration 0.061719764 m.

Minimal reproduction:

The standalone script is in #3773. The executable regression in newton/tests/test_mpr.py calls create_solve_mpr(support_map).core directly, so broad phase, contact reduction, and dynamics solvers are not involved.

Summary by CodeRabbit

  • Bug Fixes

    • Improved collision detection for small convex shapes contacting large mesh triangles.
    • Improved contact positioning, normals, and penetration depth accuracy across differently sized and coplanar shapes.
    • Preserved consistent collision results near shared triangle edges, including fallback contact scenarios.
    • Improved reliability when handling degenerate triangle geometry and coincident shape centers.
  • Tests

    • Added regression coverage for triangle-versus-convex collisions, including large triangles, coplanar cylinders, shared edges, and witness data.

@linux-foundation-easycla

linux-foundation-easycla Bot commented Aug 2, 2026

Copy link
Copy Markdown

CLA Signed
The committers listed above are authorized under a signed CLA.

  • ✅ login: LuyiLi / name: LuyiLi (06d2350)

@LuyiLi
LuyiLi had a problem deploying to external-pr-approval August 2, 2026 14:16 — with GitHub Actions Error
@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro Plus

Run ID: 818f3172-0e8b-4de8-9558-67fbf78d7573

📥 Commits

Reviewing files that changed from the base of the PR and between ee84505 and 06d2350.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • newton/_src/geometry/mpr.py
  • newton/tests/test_mpr.py
 ____________________________
< Copilot has nothing on me. >
 ----------------------------
  \
   \   \
        \ /\
        ( )
      .( o ).
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@LuyiLi
LuyiLi had a problem deploying to external-pr-approval August 2, 2026 14:16 — with GitHub Actions Error
@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

MPR triangle center initialization now applies bounded centroid nudging and triangle-normal fallbacks for coincident centers. CPU regression tests cover scale-dependent contacts, coplanar cases, and shared-edge witnesses. The changelog records the fix.

Changes

MPR contact correction

Layer / File(s) Summary
Bounded triangle center initialization
newton/_src/geometry/mpr.py, CHANGELOG.md
Triangle center initialization validates face geometry, limits centroid-directed nudging, preserves degenerate projections, and adds triangle-normal fallback handling. The changelog records the correction.
MPR contact regression coverage
newton/tests/test_mpr.py
CPU Warp tests validate cylinder penetration accuracy, coplanar handling, face normals, and box witnesses across shared triangle edges.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related issues

  • newton-physics/newton#3773: Both changes update MPR triangle–convex initialization for scale-dependent contacts and coplanar/shared-edge fallback behavior.

Possibly related PRs

  • newton-physics/newton#2651: Both changes modify MPR triangle/convex center initialization for contact errors related to scale or origin.

Suggested reviewers: nvtw, adenzler-nvidia

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary fix for scale-dependent MPR contacts on large mesh triangles.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
newton/_src/geometry/mpr.py (1)

239-257: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Shorten the inline rationale.

Lines 239-257 contain detailed failure analysis that makes this local branch difficult to scan. Keep the reason for the nudge and its 0.01 bound here. Move the extended manifold explanation to a design note or issue.

As per path instructions, comments must be brief and explain non-obvious reasons rather than narrate implementation details.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@newton/_src/geometry/mpr.py` around lines 239 - 257, Shorten the inline
comments around the triangle-centroid nudge to state only that it improves
manifold quality and limits tangential displacement to 1% (0.01) of the normal
center-to-plane distance. Remove the detailed shared-edge, manifold-builder,
force-distribution, torque, and MPR convergence analysis from this branch,
relocating it to the appropriate design note or issue.

Sources: Coding guidelines, Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@newton/_src/geometry/mpr.py`:
- Around line 267-270: Update the face-normal guard in the centroid-nudge logic
near center_a so it uses the degenerate-triangle threshold from
closest_point_on_triangle: require face_normal_length to exceed 1.0e-10, or
equivalently compare squared length against 1.0e-20. Add a regression case
covering the boundary and verifying near-degenerate triangles retain proj rather
than receiving a nudge.

In `@newton/tests/test_mpr.py`:
- Around line 108-115: Update the test docstrings in newton/tests/test_mpr.py at
lines 108-115 and 144-150 to begin with concise imperative one-line summaries:
make test_small_cylinder_on_large_triangle start with the requested face-normal
resolution summary, and make the other test start with the requested shared-edge
witness summary; retain the existing explanatory details after each summary.

---

Nitpick comments:
In `@newton/_src/geometry/mpr.py`:
- Around line 239-257: Shorten the inline comments around the triangle-centroid
nudge to state only that it improves manifold quality and limits tangential
displacement to 1% (0.01) of the normal center-to-plane distance. Remove the
detailed shared-edge, manifold-builder, force-distribution, torque, and MPR
convergence analysis from this branch, relocating it to the appropriate design
note or issue.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro Plus

Run ID: 818f3172-0e8b-4de8-9558-67fbf78d7573

📥 Commits

Reviewing files that changed from the base of the PR and between ee84505 and 06d2350.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • newton/_src/geometry/mpr.py
  • newton/tests/test_mpr.py

Comment thread newton/_src/geometry/mpr.py Outdated
Comment thread newton/tests/test_mpr.py
@LuyiLi
LuyiLi requested a deployment to external-pr-approval August 3, 2026 08:34 — with GitHub Actions Waiting
@LuyiLi
LuyiLi requested a deployment to external-pr-approval August 3, 2026 08:34 — with GitHub Actions Waiting

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
newton/_src/geometry/mpr.py (1)

233-283: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider extracting the duplicated triangle-projection logic.

Both blocks recompute tri_a, tri_b, tri_c, face_normal, face_normal_length_sq, the degenerate-threshold check, and the centroid/to_centroid tangential projection almost identically. This duplication is the reason the two blocks previously diverged on the degenerate-normal threshold (1.0e-12 vs 1.0e-20), an issue already flagged and fixed in this PR. Extracting a shared @wp.func helper (e.g., returning tri_a, tri_b, tri_c, face_normal_unit, face_normal_valid, centroid) would remove this recurring drift risk between geometric_center and solve_mpr_core.

This is not required before merge, since both sites are currently consistent, but it reduces future maintenance risk given the prior incident.

♻️ Sketch of a shared helper
`@wp.func`
def _triangle_face_geometry(geom_a: Any) -> tuple[wp.vec3, wp.vec3, wp.vec3, wp.vec3, bool]:
    """Return triangle vertices, unit face normal, and validity for shape A."""
    tri_a = wp.vec3(0.0, 0.0, 0.0)
    tri_b = geom_a.scale
    tri_c = geom_a.auxiliary
    face_normal = wp.cross(tri_b - tri_a, tri_c - tri_a)
    face_normal_length_sq = wp.length_sq(face_normal)
    valid = face_normal_length_sq >= 1.0e-20
    face_normal_unit = wp.vec3(0.0, 0.0, 0.0)
    if valid:
        face_normal_unit = face_normal / wp.sqrt(face_normal_length_sq)
    return tri_a, tri_b, tri_c, face_normal_unit, valid

Both geometric_center and solve_mpr_core can then call this helper instead of repeating the derivation.

Also applies to: 358-395

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@newton/_src/geometry/mpr.py` around lines 233 - 283, Extract the shared
triangle face-geometry derivation from geometric_center and solve_mpr_core into
a single `@wp.func` helper, returning the triangle vertices, normalized face
normal, and validity flag using the consistent 1.0e-20 threshold. Update both
callers to use the helper while preserving their existing projection and
centroid-nudge behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@newton/_src/geometry/mpr.py`:
- Around line 233-283: Extract the shared triangle face-geometry derivation from
geometric_center and solve_mpr_core into a single `@wp.func` helper, returning the
triangle vertices, normalized face normal, and validity flag using the
consistent 1.0e-20 threshold. Update both callers to use the helper while
preserving their existing projection and centroid-nudge behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro Plus

Run ID: e9b22bcb-99a9-499c-b2fb-bd2dd66f70b9

📥 Commits

Reviewing files that changed from the base of the PR and between 06d2350 and cbb22e9.

📒 Files selected for processing (2)
  • newton/_src/geometry/mpr.py
  • newton/tests/test_mpr.py

@LuyiLi
LuyiLi marked this pull request as ready for review August 3, 2026 08:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] MPR can return metre-scale penetration and nonlocal witnesses for small convex shapes on large triangles

1 participant