@@ -168,29 +168,41 @@ def __init__(self, cfg: InteractiveSceneCfg):
168168 # the template is authoritative; the regex form is the same namespace spelled for matching
169169 self ._env_fmt = self .cloner_cfg .clone_template
170170 self .env_prim_paths = [self ._env_fmt .format (i ) for i in range (self .cfg .num_envs )]
171- self ._scene_asset_names : list [str ] = []
172- self ._clone_valid_set : np .ndarray | None = None
171+ self ._ALL_INDICES = torch .arange (self .cfg .num_envs , dtype = torch .long , device = self .device )
173172
174173 self ._global_prim_paths = list ()
175- clone_cfgs , global_paths = self ._collect_asset_cfgs ()
176- scene_from_cfg = bool (self ._scene_asset_names )
174+ asset_cfgs , global_paths , valid_set = self ._collect_asset_cfgs ()
175+ scene_from_cfg = any (
176+ name not in InteractiveSceneCfg .__dataclass_fields__ and cfg is not None
177+ for name , cfg in self .cfg .__dict__ .items ()
178+ )
177179 if scene_from_cfg :
178180 with cloner .ReplicateSession (
179- clone_cfgs ,
181+ asset_cfgs ,
180182 num_clones = self .num_envs ,
181183 env_spacing = self .cfg .env_spacing ,
182184 global_paths = global_paths ,
183185 env_template = self ._env_fmt ,
184186 clone_strategy = self .cloner_cfg .clone_strategy ,
185- valid_set = self . _clone_valid_set ,
187+ valid_set = valid_set ,
186188 replicate_physics = self .cloner_cfg .replicate_physics ,
187189 ) as session :
188- self ._author_envs (session .plan .env_ids , session .plan .positions )
190+ self .stage .DefinePrim (self .env_prim_paths [0 ], "Xform" )
191+ with cloner .disabled_fabric_change_notifies (self .stage , restore = False ):
192+ cloner .usd_replicate (
193+ self .stage ,
194+ [self .env_prim_paths [0 ]],
195+ [self ._env_fmt ],
196+ session .plan .env_ids ,
197+ positions = session .plan .positions ,
198+ )
189199 self ._add_entities_from_cfg ()
200+ positions = session .plan .positions
190201 else :
191- env_ids = np .arange (self .num_envs , dtype = np .int64 )
192- env_origins = cloner .grid_transforms (self .num_envs , self .cfg .env_spacing )[0 ]
193- self ._author_envs (env_ids , env_origins )
202+ self .stage .DefinePrim (self .env_prim_paths [0 ], "Xform" )
203+ positions = cloner .grid_transforms (self .num_envs , self .cfg .env_spacing )[0 ]
204+ self ._env_origins = torch .as_tensor (positions , device = self .device )
205+ self ._env_origins_plan = self .sim .get_clone_plan ()
194206
195207 # Every sensor exists by now, so all visualizer and camera-renderer requirements are visible.
196208 cam_types = [s .cfg .renderer_cfg .renderer_type for s in self ._sensors .values () if isinstance (s .cfg , CameraCfg )]
@@ -203,17 +215,17 @@ def __init__(self, cfg: InteractiveSceneCfg):
203215 if self .cfg .filter_collisions and "physx" in self .physics_backend and scene_from_cfg :
204216 self .filter_collisions (self ._global_prim_paths )
205217
206- def _collect_asset_cfgs (self ) -> tuple [list [Any ], tuple [str , ...]]:
218+ def _collect_asset_cfgs (self ) -> tuple [list [Any ], tuple [str , ...], np . ndarray | None ]:
207219 """Flatten user-declared cfgs and declare shared prim roots for clone planning.
208220
209221 Expands :class:`~isaaclab.assets.RigidObjectCollectionCfg` into its members,
210222 resolves ``{ENV_REGEX_NS}`` macros, lets an enclosing asset's row own nested materials,
211- and returns only env-scoped configs with a spawner. Global roots are returned separately .
223+ and returns env-scoped configs with a spawner, global roots, and valid clone combinations .
212224 """
213225
214226 cfg_fields = InteractiveSceneCfg .__dataclass_fields__
215227 items = [(name , cfg ) for name , cfg in self .cfg .__dict__ .items () if name not in cfg_fields and cfg is not None ]
216- self . _scene_asset_names = [name for name , _ in items ]
228+ scene_asset_names = [name for name , _ in items ]
217229 flat_items : list [tuple [str , Any ]] = []
218230 for asset_name , asset_cfg in items :
219231 children = (
@@ -239,7 +251,7 @@ def _collect_asset_cfgs(self) -> tuple[list[Any], tuple[str, ...]]:
239251 and any (cloner .path .relative_to (cfg .prim_path , owner ) not in (None , "" ) for owner in owner_paths )
240252 }
241253 nested_material_names = {name for name , cfg in flat_items if id (cfg ) in nested_visual_material_ids }
242- self . _scene_asset_names = [name for name in self . _scene_asset_names if name not in nested_material_names ]
254+ scene_asset_names = [name for name in scene_asset_names if name not in nested_material_names ]
243255
244256 cfgs : list [Any ] = []
245257 global_paths : tuple [str , ...] = ()
@@ -259,15 +271,15 @@ def _collect_asset_cfgs(self) -> tuple[list[Any], tuple[str, ...]]:
259271 variant_counts .append (cloner .num_spawn_variants (child .spawn ))
260272
261273 if self .cloner_cfg .clone_combinations and clone_asset_names :
262- self . _clone_valid_set = cloner .make_valid_clone_combinations (
274+ valid_set = cloner .make_valid_clone_combinations (
263275 clone_asset_names ,
264276 variant_counts ,
265277 self .cloner_cfg .clone_combinations ,
266- all_asset_names = self . _scene_asset_names ,
278+ all_asset_names = scene_asset_names ,
267279 )
268280 else :
269- self . _clone_valid_set = None
270- return cfgs , global_paths
281+ valid_set = None
282+ return cfgs , global_paths , valid_set
271283
272284 def filter_collisions (self , global_prim_paths : list [str ] | None = None ):
273285 """Filter environments collisions.
@@ -371,10 +383,9 @@ def env_origins(self) -> torch.Tensor:
371383 if self ._terrain is not None :
372384 return self ._terrain .env_origins
373385 plan = self .sim .get_clone_plan ()
374- if plan is not self ._env_origins_plan :
386+ if plan is not None and plan is not self ._env_origins_plan :
387+ self ._env_origins = torch .as_tensor (plan .positions , device = self .device )
375388 self ._env_origins_plan = plan
376- if plan is not None and plan .positions is not None :
377- self ._env_origins = torch .as_tensor (plan .positions , device = self .device )
378389 return self ._env_origins
379390
380391 @property
@@ -779,15 +790,6 @@ def __getitem__(self, key: str) -> Any:
779790 Internal methods.
780791 """
781792
782- def _author_envs (self , env_ids : np .ndarray , positions : np .ndarray ) -> None :
783- """Author environment roots from the active layout."""
784- self ._ALL_INDICES = torch .as_tensor (env_ids , device = self .device )
785- self ._env_origins = torch .as_tensor (positions , device = self .device )
786- self ._env_origins_plan = self .sim .get_clone_plan ()
787- self .stage .DefinePrim (self .env_prim_paths [0 ], "Xform" )
788- with cloner .disabled_fabric_change_notifies (self .stage , restore = False ):
789- cloner .usd_replicate (self .stage , [self .env_prim_paths [0 ]], [self ._env_fmt ], env_ids , positions = positions )
790-
791793 def _add_entities_from_cfg (self ): # noqa: C901
792794 """Add scene entities from the config."""
793795 from isaaclab_physx .assets import SurfaceGripperCfg # noqa: PLC0415
0 commit comments