Skip to content
Open
2 changes: 1 addition & 1 deletion source/isaaclab/config/extension.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]

# Note: Semantic Versioning is used: https://semver.org/
version = "0.48.4"
version = "0.49.0"

# Description
title = "Isaac Lab framework for Robot Learning"
Expand Down
33 changes: 33 additions & 0 deletions source/isaaclab/docs/CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,39 @@
Changelog
---------


0.49.0 (2025-11-14)
~~~~~~~~~~~~~~~~~~~

* Removed hard dependency on the Isaac Sim Cloner for scene replication. Replication now uses internal utilities
:func:`~isaaclab.scene.cloner.usd_replicate` and :func:`~isaaclab.scene.cloner.physx_replicate`, reducing coupling
to Isaac Sim. Public APIs in :class:`~isaaclab.scene.interactive_scene.InteractiveScene` remain unchanged; code
directly importing the external Cloner should migrate to these utilities.


Added
^^^^^

* Added optional random prototype selection during environment cloning in
:class:`~isaaclab.scene.interactive_scene.InteractiveScene` via
:attr:`~isaaclab.scene.interactive_scene_cfg.InteractiveSceneCfg.random_heterogenous_cloning`.
Defaults to ``True``; round-robin (modulo) mapping remains available by setting it to ``False``.

* Added flexible per-object cloning path in
:class:`~isaaclab.scene.interactive_scene.InteractiveScene`: when environments are heterogeneous
(different prototypes across envs), replication switches to per-object instead of whole-env cloning.
This reduces PhysX cloning time in heterogeneous scenes.


Deprecated
^^^^^^^^^^

* Deprecated :attr:`~isaaclab.sim.spawners.wrappers.MultiAssetSpawnerCfg.random_choice` and
:attr:`~isaaclab.sim.spawners.wrappers.MultiUsdFileCfg.random_choice`. Use
:attr:`~isaaclab.scene.interactive_scene_cfg.InteractiveSceneCfg.random_heterogenous_cloning` to control whether
assets are selected randomly (``True``) or via round-robin (``False``) across environments.


0.48.4 (2025-11-14)
~~~~~~~~~~~~~~~~~~~

Expand Down
8 changes: 1 addition & 7 deletions source/isaaclab/isaaclab/assets/asset_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,8 @@ def __init__(self, cfg: AssetBaseCfg):
# get stage handle
self.stage = get_current_stage()

# check if base asset path is valid
# note: currently the spawner does not work if there is a regex pattern in the leaf
# For example, if the prim path is "/World/Robot_[1,2]" since the spawner will not
# know which prim to spawn. This is a limitation of the spawner and not the asset.
asset_path = self.cfg.prim_path.split("/")[-1]
asset_path_is_regex = re.match(r"^[a-zA-Z0-9/_]+$", asset_path) is None
# spawn the asset
if self.cfg.spawn is not None and not asset_path_is_regex:
if self.cfg.spawn is not None:
self.cfg.spawn.func(
self.cfg.prim_path,
self.cfg.spawn,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,17 +67,10 @@ def __init__(self, cfg: RigidObjectCollectionCfg):
self.cfg = cfg.copy()
# flag for whether the asset is initialized
self._is_initialized = False
self._prim_paths = []
# spawn the rigid objects
for rigid_object_cfg in self.cfg.rigid_objects.values():
# check if the rigid object path is valid
# note: currently the spawner does not work if there is a regex pattern in the leaf
# For example, if the prim path is "/World/Object_[1,2]" since the spawner will not
# know which prim to spawn. This is a limitation of the spawner and not the asset.
asset_path = rigid_object_cfg.prim_path.split("/")[-1]
asset_path_is_regex = re.match(r"^[a-zA-Z0-9/_]+$", asset_path) is None
# spawn the asset
if rigid_object_cfg.spawn is not None and not asset_path_is_regex:
if rigid_object_cfg.spawn is not None:
rigid_object_cfg.spawn.func(
rigid_object_cfg.prim_path,
rigid_object_cfg.spawn,
Expand All @@ -88,7 +81,7 @@ def __init__(self, cfg: RigidObjectCollectionCfg):
matching_prims = sim_utils.find_matching_prims(rigid_object_cfg.prim_path)
if len(matching_prims) == 0:
raise RuntimeError(f"Could not find prim with path {rigid_object_cfg.prim_path}.")
self._prim_paths.append(rigid_object_cfg.prim_path)

# stores object names
self._object_names_list = []

Expand Down Expand Up @@ -747,7 +740,7 @@ def _on_prim_deletion(self, prim_path: str) -> None:
if prim_path == "/":
self._clear_callbacks()
return
for prim_path_expr in self._prim_paths:
for prim_path_expr in [obj.prim_path for obj in self.cfg.rigid_objects.values()]:
result = re.match(
pattern="^" + "/".join(prim_path_expr.split("/")[: prim_path.count("/") + 1]) + "$", string=prim_path
)
Expand Down
Loading
Loading