diff --git a/src/mjviser/scene.py b/src/mjviser/scene.py index 19a3e64..46b76bf 100644 --- a/src/mjviser/scene.py +++ b/src/mjviser/scene.py @@ -274,6 +274,38 @@ def set_refresh_handler(self, handler: Callable[[], None] | None) -> None: with self._update_lock: self._refresh_handler = handler + def rebuild_visual_handles(self) -> None: + """Rebuild handles whose geometry or appearance is baked at creation time.""" + with self._update_lock: + for group in self._mesh_groups: + group.handle.remove() + self._mesh_groups.clear() + + for handle in self._fixed_geom_handles.values(): + handle.remove() + self._fixed_geom_handles.clear() + + for handle in self._fixed_site_handles.values(): + handle.remove() + self._fixed_site_handles.clear() + + for handle in self.site_handles_by_group.values(): + handle.remove() + self.site_handles_by_group.clear() + + self._clear_hull_handles() + self._hull_body_meshes.clear() + self._hull_mesh_bodies.clear() + + mujoco.mj_kinematics(self.mj_model, self.mj_data) + self._add_fixed_geometry() + self._create_mesh_handles_by_group() + self._add_fixed_sites() + self._create_site_handles_by_group() + self._compute_hull_body_meshes() + self._build_hull_handles() + self._sync_visibilities() + def _apply_visualization_change(self, mutator: Callable[[], None]) -> None: """Apply a GUI-side visualization change and refresh from cached state.""" refresh_handler: Callable[[], None] | None = None diff --git a/tests/test_scene.py b/tests/test_scene.py index 03f8594..c3c7ea1 100644 --- a/tests/test_scene.py +++ b/tests/test_scene.py @@ -125,6 +125,21 @@ def test_scene_default_visibility(scene): assert scene.geom_groups_visible[3:] == [False, False, False] +def test_rebuild_visual_handles_recreates_baked_mesh_handles(scene, simple_model): + old_handles = [group.handle for group in scene._mesh_groups] + assert old_handles + + box_id = mujoco.mj_name2id(simple_model, mujoco.mjtObj.mjOBJ_GEOM, "box") + simple_model.geom_rgba[box_id] = [0.0, 0.0, 1.0, 1.0] + + scene.rebuild_visual_handles() + + new_handles = [group.handle for group in scene._mesh_groups] + assert new_handles + old_handle_ids = {id(handle) for handle in old_handles} + assert all(id(handle) not in old_handle_ids for handle in new_handles) + + # Batched transform--------------------------------------------------- diff --git a/uv.lock b/uv.lock index 5e6046e..d08def2 100644 --- a/uv.lock +++ b/uv.lock @@ -657,7 +657,7 @@ wheels = [ [[package]] name = "mjviser" -version = "0.0.12" +version = "0.0.13" source = { editable = "." } dependencies = [ { name = "mujoco" },