Skip to content

[Bug Report] CCD effectively disabled for mesh/box/hfield pairs when margin=0 (is_discrete path) #5020

@jkkim-irim

Description

@jkkim-irim

Summary

Continuous Collision Detection (CCD) is effectively not applied for mesh/box/hfield pairs when both geoms have margin = 0. The code path behaves like a discrete contact check that hits the iteration limit and exits early. Because of that, the "ccd_iterations needs to be increased" warning was firing every time, so it is currently commented out in the code. True tolerance-based CCD only runs when at least one geom has a non-zero margin (e.g. 0.001).

Environment

  • Isaac Lab (dev/newton)
  • MuJoCo warp / Newton (mujoco_warp collision pipeline)
  • Relevant code: mujoco_warp/_src/collision_gjk.py (and related CCD/GJK usage)

Root cause (from code)

  1. is_discrete
    For mesh/box/hfield pairs, when both geoms have margin == 0, the CCD path sets is_discrete = True (see collision_gjk.py, e.g. around _discrete_geoms and the is_discrete assignment in ccd()).

  2. GJK convergence when is_discrete=True
    When is_discrete is True, the GJK convergence threshold is set to:

    • epsilon = 0 (e.g. epsilon = wp.where(is_discrete, 0.0, 0.5 * tolerance * tolerance)),
      so the loop only stops when the distance to the origin is exactly 0 (or within that strict criterion).
  3. Numerical behavior
    With finite precision, that condition is almost never satisfied. The loop therefore runs until gjk_iterations (or ccd_iterations) is reached and then exits. So:

    • There is no meaningful "tolerance-based" convergence.
    • The code behaves like a discrete "are they touching?" check that always hits the iteration limit.
  4. Result

    • Name: "CCD" (continuous collision detection).
    • Actual behavior for margin=0 mesh/box/hfield: discrete-style check + iteration limit, with the "iteration limit reached" warning printed repeatedly.
    • True CCD (trajectory tracking, tolerance-based convergence) is not applied in this configuration.
  5. When CCD actually runs
    If margin is non-zero (e.g. 0.001) for at least one of the geoms, is_discrete becomes False. Then:

    • A non-zero epsilon (tolerance) is used for GJK convergence.
    • The loop can terminate on tolerance, and tolerance-based continuous collision detection is applied as intended.

Repeated warning and current workaround

Because GJK almost always runs to the iteration limit when is_discrete=True (margin=0 mesh/box/hfield), the warning that indicates "ccd_iterations needs to be increased" was triggered every time this code path ran (e.g. per contact pair per step). That made the warning effectively spam the log. As a result, that warning is currently commented out in the code (see collision_gjk.py around lines 670–671: the wp.printf("Warning: opt.ccd_iterations, ...") is commented). So the situation is: (1) CCD is effectively disabled for margin=0 discrete geoms, (2) the only visible symptom was this repeated warning, and (3) the immediate mitigation was to comment out the warning rather than fix the root cause. A proper fix is to enable tolerance-based CCD (e.g. via non-zero contact_margin / geom margin) so that convergence is achieved and the warning is no longer needed, or to treat the margin=0 discrete case explicitly (e.g. as discrete contact only, without claiming CCD).

Expected vs actual

Aspect Expected Actual (margin=0 mesh/box/hfield)
CCD role Tolerance-based continuous collision detection (trajectory, penetration depth). Effectively disabled; behaves like discrete check + iteration limit.
Warnings None or rare. "Iteration limit" warning fired repeatedly → now commented out.
Convergence GJK stops when distance < tolerance. GJK almost always runs to full iteration count.

Suggested fix / Newton integration

  • Solver / model: The solver should pass model.shape_contact_margin (or equivalent) to the MuJoCo geom margin so that mesh/box/hfield pairs do not always get margin=0 in the CCD path.
  • Builder / defaults: In Newton, builder.default_shape_cfg.contact_margin (or equivalent) should be set to a small non-zero value (e.g. 0.001) where appropriate, and that value should flow through to the geom margin used in the collision/CCD code.

That way, the CCD path uses the tolerance-based (is_discrete=False) branch and real CCD is applied instead of the current "discrete + iteration limit" behavior.

Conclusion

For mesh/box/hfield pairs with margin=0, CCD was effectively disabled; the iteration-limit warning was a side effect (GJK never converging under epsilon=0) and was eventually commented out to avoid log spam. Enabling non-zero margin (via contact_margin / shape_contact_margin) restores proper tolerance-based CCD behavior and makes the warning unnecessary.

Image

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions