From 58c37abeb6b67760463993e1fd5bc93da7892bbf Mon Sep 17 00:00:00 2001 From: Will Compton Date: Wed, 8 Jul 2026 22:35:17 -0700 Subject: [PATCH] Bump MuJoCo 3.1.6 -> 3.8.1 (fixes mj_multiRay culling misses at slab seams) mj_multiRay in MuJoCo <= 3.4 computes per-geom angular culling windows from AABB corners with no margin, so large thin ground slabs adjacent to the ray origin (e.g. standing near a seam between two ground boxes) get culled for steep rays: the simulated lidar reports whatever lies below instead of the slab top face. 3.5.0 added a distance-dependent angular margin that fixes this (verified empirically: 103/120 seam rays wrong on 3.1.6, 0/120 on 3.8.1). Breaking API change absorbed: mj_ray / mj_multiRay grew a surface-normal output argument in 3.5.0 -- pass nullptr at both CastRays call sites. Co-Authored-By: Claude Fable 5 --- obelisk/cpp/obelisk_cpp/CMakeLists.txt | 4 +++- obelisk/cpp/obelisk_cpp/include/obelisk_mujoco_sim_robot.h | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/obelisk/cpp/obelisk_cpp/CMakeLists.txt b/obelisk/cpp/obelisk_cpp/CMakeLists.txt index 641624df..8eeadff6 100644 --- a/obelisk/cpp/obelisk_cpp/CMakeLists.txt +++ b/obelisk/cpp/obelisk_cpp/CMakeLists.txt @@ -40,7 +40,9 @@ if(USE_MUJOCO) find_package(Eigen3 REQUIRED) include(FetchContent) - set(MUJOCO_VERSION "3.1.6" CACHE STRING "mujoco version") + # >= 3.5.0 required: mj_multiRay's angular culling in <= 3.4 wrongly drops + # large slabs near the ray origin (below-ground lidar returns at slab seams) + set(MUJOCO_VERSION "3.8.1" CACHE STRING "mujoco version") set(COMP_ARCH "x86_64" CACHE STRING "computer architecture") FetchContent_Declare( diff --git a/obelisk/cpp/obelisk_cpp/include/obelisk_mujoco_sim_robot.h b/obelisk/cpp/obelisk_cpp/include/obelisk_mujoco_sim_robot.h index 68799cba..e025dd24 100644 --- a/obelisk/cpp/obelisk_cpp/include/obelisk_mujoco_sim_robot.h +++ b/obelisk/cpp/obelisk_cpp/include/obelisk_mujoco_sim_robot.h @@ -1539,16 +1539,18 @@ namespace obelisk { Eigen::Matrix dirs_rm = dirs_w; std::vector geomids(num_rays, -1); const mjtNum cutoff = iface.get_max_distance() > 0.0 ? iface.get_max_distance() : mjMAXVAL; + // mujoco >= 3.5: ray functions take an optional surface-normal + // output (nullptr = not needed) mj_multiRay(this->model_, this->data_, origin.data(), dirs_rm.data(), iface.get_geom_group_mask(), 1, -1, geomids.data(), dists.data(), - num_rays, cutoff); + nullptr, num_rays, cutoff); } else { int geom_id[1] = { -1 }; for (int ii = 0; ii < num_rays; ++ii) { Eigen::Vector3d ray_origin = starts_w.row(ii).transpose(); Eigen::Vector3d direction = dirs_w.row(ii).transpose(); dists[ii] = mj_ray(this->model_, this->data_, ray_origin.data(), direction.data(), - iface.get_geom_group_mask(), 1, -1, geom_id); + iface.get_geom_group_mask(), 1, -1, geom_id, nullptr); } } }