Skip to content

Comments

Fix heightfield scene BVH bounds missing upper z-range#1175

Merged
kevinzakka merged 1 commit intogoogle-deepmind:mainfrom
kevinzakka:fix-hfield-bvh-bounds
Feb 23, 2026
Merged

Fix heightfield scene BVH bounds missing upper z-range#1175
kevinzakka merged 1 commit intogoogle-deepmind:mainfrom
kevinzakka:fix-hfield-bvh-bounds

Conversation

@kevinzakka
Copy link
Collaborator

@kevinzakka kevinzakka commented Feb 22, 2026

The scene-level BVH bounds for heightfield geoms were computed with _compute_box_bounds(pos, rot, size), which creates an AABB symmetric around the geom position. However, heightfield mesh vertices have z-values in [0, max_z], extending upward from the geom origin rather than being centered on it. This caused the upper half of the surface to fall outside the bounding volume, so rays aimed at the top of the heightfield skipped intersection entirely.

Fix by offsetting the AABB center in-place using the existing half-extent. Since hfield z-values start at 0, size[2] (the z half-extent) equals the center offset:

hfield_center = pos + rot @ wp.vec3(0.0, 0.0, size[2])
_compute_box_bounds(hfield_center, rot, size)

This is a minimal 2-line change in _compute_bvh_bounds with no new arrays, fields, or plumbing required.

In local coordinates:

  • Mesh z range: [0, max_z]
  • Old AABB z range: [-max_z/2, +max_z/2] (centered at geom origin, misses the top half)
  • New AABB z range: [0, max_z] (centered at max_z/2, tight fit)

Note: This works because MuJoCo's compiler always normalizes hfield_data to [0, 1] by subtracting the minimum value (ref), so pmin_z = 0 and center_z = half_z = size[2].

Thanks to @slambert-bd for flagging this.

@kevinzakka kevinzakka force-pushed the fix-hfield-bvh-bounds branch from f73308f to b88316b Compare February 23, 2026 01:26
@kevinzakka kevinzakka requested a review from StafaH February 23, 2026 01:29
@StafaH
Copy link
Collaborator

StafaH commented Feb 23, 2026

LGTM!

@kevinzakka kevinzakka requested a review from thowell February 23, 2026 05:45
elif type == GeomType.HFIELD:
size = hfield_bounds_size[geom_dataid[geom_id]]
lower_bound, upper_bound = _compute_box_bounds(pos, rot, size)
hfield_center = pos + rot @ wp.vec3(0.0, 0.0, size[2])
Copy link
Collaborator

Choose a reason for hiding this comment

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

maybe something like rot[:, 2] * size[2]?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done, thanks Taylor.

Simplify hfield BVH center offset computation per review.
@kevinzakka kevinzakka force-pushed the fix-hfield-bvh-bounds branch from b88316b to 658e86b Compare February 23, 2026 16:07
@kevinzakka kevinzakka merged commit 0f36e04 into google-deepmind:main Feb 23, 2026
10 checks passed
@kevinzakka kevinzakka deleted the fix-hfield-bvh-bounds branch February 23, 2026 16:21
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.

3 participants