When two geoms are close but the expected contact response is missing, first identify which pair definition supplies the parameters. Then compare the surface separation with that pair’s detection and activation distances. Changing a gap value on a geom may not affect an explicitly named pair, and finding a contact record is not the same as finding an ordinary active contact constraint.
An actual Blender geometry experiment measured four positive surface gaps. Applying the documented MuJoCo 3.15.0 distance rules gives different classifications for the same geometry. The experiment checks the geometric measurement; the contact classifications come from the versioned documentation and pinned code. MuJoCo itself was not run, and no contact count or force was measured.
Read two distances, not one
In the captured 3.15.0 computation reference, margin determines the activation distance, while gap extends detection beyond that margin. Away from equality boundaries, a surface separation greater than margin + gap is outside detection; a separation between margin and margin + gap lies in the inactive band; a separation below margin lies in the active band. These are distance regimes, subject to the pair surviving the other collision checks. The distinction comes from the MuJoCo computation reference.
An inactive contact can be recorded without an ordinary contact constraint. That does not mean no force mechanism of any kind can use it: the documentation specifically allows custom computations and adhesion-related uses of inactive contacts. Conversely, classifying a distance as active does not determine a nonzero force magnitude. That requires the rest of the model and solver state, which this example does not evaluate.
For the first configuration, assign each geom a margin of 2.5 mm and a gap of 1 mm. The inspected code sums the two geom margins and the two geom gaps, giving a pair margin of 5 mm and a pair gap of 2 mm. Detection therefore extends to 7 mm; the ordinary active distance region begins at the 5 mm boundary. This comparison assumes no global margin override and that the pair passes the other collision eligibility checks.
Now name the same two geoms in an explicit pair and assign that pair a margin of 2 mm and a gap of 3 mm. Its detection boundary is 5 mm and its activation boundary is 2 mm. The individual geom values are not the source of those explicit-pair properties. The versioned XML reference describes this distinction between inferred geom properties and explicitly supplied pair properties.
At a declared separation of 6 mm, the dynamic configuration is in its inactive distance band, while the explicit configuration is outside its detection distance. At 4 mm, the dynamic configuration is in its active band and the explicit configuration is in its inactive band. At 9 mm, both are outside detection; at 1 mm, both are in their active bands. None of these four values sits on an equality boundary.
Keep the geometric measurement separate
We ran this AI-operated numerical experiment in Blender 5.2.2 LTS on 6 October 2026. Each of four separate static arrangements used two finite boxes, each 40 × 25 × 5 mm, with matching orientations and overlapping opposing faces. Their assigned surface gaps were 9, 6, 4 and 1 mm. One translated, rotated frame put the boxes into world coordinates, so the check recovered distance from evaluated world geometry rather than treating a local z coordinate as a world distance.
For each arrangement, a Blender BVH query started at the center recovered from A’s four upper-face corners and found the nearest point on B’s complete evaluated surface. The returned point lay inside B’s finite lower face. An independent supporting-plane lower bound and interior-face witness checked the minimum separation for these aligned, overlapping faces. The raw query distances and independently calculated geometry agreed within a 0.02 mm allowance fixed before measurement. This numerical check does not measure MuJoCo’s contact accuracy, and the minimum-distance conclusion would not follow automatically for offset or differently rotated opposing faces.
Blender supplied geometry and nearest-point evidence only; it did not create or inspect MuJoCo contacts. The four alternatives occupy the same coordinate region in separate collections. They are separate configurations, not simultaneous physical contacts or a motion sequence.

Nearest distances rounded to 0.001 mm; the last two columns are source-derived distance eligibility, subject to the other collision checks:
| Assigned gap (mm) | Blender nearest (mm) | Dynamic pair | Explicit pair |
|---|---|---|---|
| 9 | 9.000 | Outside detection | Outside detection |
| 6 | 6.000 | Inactive band | Outside detection |
| 4 | 4.000 | Active band | Inactive band |
| 1 | 1.000 | Active band | Active band |
The following standalone arithmetic example reproduces the intended parameter comparison in millimetres. It deliberately leaves exact boundary cases unclassified and makes no call to MuJoCo or Blender. We executed this exact reader; its four classifications matched the source-derived comparison above.
import math
def distance_regime(d, margin, gap):
values = (d, margin, gap)
if any(isinstance(v, bool) or not isinstance(v, (int, float))
or not math.isfinite(v) or v < 0 for v in values):
raise ValueError('Use finite nonnegative distances in one unit')
if d == margin or d == margin + gap:
return 'boundary not classified'
if d > margin + gap:
return 'outside detection distance'
if d > margin:
return 'inactive distance band'
return 'active distance band'
# All values below are synthetic millimetres, not engine output.
dynamic_margin, dynamic_gap = 2.5 + 2.5, 1 + 1
pair_margin, pair_gap = 2, 3
for separation in (9, 6, 4, 1):
dynamic = distance_regime(separation, dynamic_margin, dynamic_gap)
explicit = distance_regime(separation, pair_margin, pair_gap)
print(f'{separation} mm: dynamic={dynamic}; explicit={explicit}')
assert distance_regime(5, 5, 2) == 'boundary not classified'
assert distance_regime(7, 5, 2) == 'boundary not classified'
The reader accepts nonnegative values because that is the chosen example domain; it is not a validator for every legal MuJoCo configuration. It labels a distance regime, not a number of contacts. A box pair can yield multiple contact points, so a one-row comparison should never be read as one engine contact.
Check explicit pairs before relying on body exclusion
There is a version-specific detail worth checking when an excluded body pair still appears to participate in contact processing. In the captured 3.15.0 collision driver, predefined geom pairs are processed before the body-pair exclusion check. Remaining predefined pairs are processed after the body-pair loop. Thus the body exclusion does not cancel a separately declared explicit geom pair in this inspected implementation.
The XML exclusion entry uses broader wording about geoms belonging to the two bodies. The implementation order supplies an explicit-pair exception that this wording does not spell out. Treat that as a pinned code/prose distinction, not a release-independent promise or a migration recommendation.
An explicit pair still does not guarantee a contact. Global collision settings, sleeping conditions where enabled, an available collision function, bounding checks and the detailed distance test remain relevant. For a missing or unexpected response, inspect the exact engine version, whether the pair is dynamic or explicit, the applicable margin/gap values, and the other eligibility checks before attributing the result to solver forces. If the uncertainty is earlier still—whether the shapes actually intersect—the separate bounding-box versus mesh collision experiment addresses that geometric question.
For a broader question—whether a simulated response is good enough for the real task—the simulation fidelity acceptance guide explains which measurements should be compared. Selecting a collision representation is another distinct step: the Drake hydroelastic fallback guide covers that engine’s representation and fallback conditions. Neither question is answered by making a MuJoCo pair pass its distance threshold.