Skip to content

Commit d7dca78

Browse files
Mayankm96Edify0991
authored andcommitted
Creates a minimal function to change prim properties (isaac-sim#4337)
# Description This MR introduces a simplified version of the `ChangePrimProperty` command. The original command is designed to handle complex USD layer compositions, but most of our applications do not require this level of functionality. In practice, we either do not support multiple composition layers at all, or only support limited mechanisms such as references or variants. Using the Kit-provided command also introduces unnecessary side effects, such as early stage attachment, due to its reliance on layer-resolving APIs. To avoid this extra coupling and complexity, this MR replaces the command with a lightweight implementation tailored to our actual use cases. ## Type of change - Breaking change (existing functionality will not work without user modification) ## Checklist - [x] I have read and understood the [contribution guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html) - [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with `./isaaclab.sh --format` - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [ ] I have updated the changelog and the corresponding version in the extension's `config/extension.toml` file - [ ] I have added my name to the `CONTRIBUTORS.md` or my name already exists there
1 parent b218876 commit d7dca78

File tree

11 files changed

+386
-102
lines changed

11 files changed

+386
-102
lines changed

source/isaaclab/config/extension.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22

33
# Note: Semantic Versioning is used: https://semver.org/
4-
version = "0.53.0"
4+
version = "0.53.1"
55

66
# Description
77
title = "Isaac Lab framework for Robot Learning"

source/isaaclab/docs/CHANGELOG.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
11
Changelog
22
---------
33

4+
0.53.1 (2026-01-08)
5+
~~~~~~~~~~~~~~~~~~~
6+
7+
Added
8+
^^^^^
9+
10+
* Added function :func:`~isaaclab.sim.utils.prims.change_prim_property` to change attributes on a USD prim.
11+
This replaces the previously used USD command ``ChangeProperty`` that depends on Omniverse Kit API.
12+
13+
Changed
14+
^^^^^^^
15+
16+
* Replaced occurrences of ``ChangeProperty`` USD command to :func:`~isaaclab.sim.utils.prims.change_prim_property`.
17+
18+
419
0.53.0 (2026-01-07)
520
~~~~~~~~~~~~~~~~~~~
621

source/isaaclab/isaaclab/markers/visualization_markers.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import torch
2525
from dataclasses import MISSING
2626

27-
import omni.kit.commands
2827
import omni.physx.scripts.utils as physx_utils
2928
from pxr import Gf, PhysxSchema, Sdf, Usd, UsdGeom, UsdPhysics, Vt
3029

@@ -396,18 +395,12 @@ def _process_prototype_prim(self, prim: Usd.Prim):
396395
child_prim.SetInstanceable(False)
397396
# check if prim is a mesh -> if so, make it invisible to secondary rays
398397
if child_prim.IsA(UsdGeom.Gprim):
399-
# early attach stage to usd context if stage is in memory
400-
# since stage in memory is not supported by the "ChangePropertyCommand" kit command
401-
sim_utils.attach_stage_to_usd_context(attaching_early=True)
402-
403398
# invisible to secondary rays such as depth images
404-
omni.kit.commands.execute(
405-
"ChangePropertyCommand",
406-
prop_path=Sdf.Path(f"{child_prim.GetPrimPath().pathString}.primvars:invisibleToSecondaryRays"),
399+
sim_utils.change_prim_property(
400+
prop_path=f"{child_prim.GetPrimPath().pathString}.primvars:invisibleToSecondaryRays",
407401
value=True,
408-
prev=None,
402+
stage=prim.GetStage(),
409403
type_to_create_if_not_exist=Sdf.ValueTypeNames.Bool,
410-
usd_context_name=prim.GetStage(),
411404
)
412405
# add children to list
413406
all_prims += child_prim.GetChildren()

source/isaaclab/isaaclab/sim/converters/mesh_converter.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from isaaclab.sim.converters.asset_converter_base import AssetConverterBase
1616
from isaaclab.sim.converters.mesh_converter_cfg import MeshConverterCfg
1717
from isaaclab.sim.schemas import schemas
18-
from isaaclab.sim.utils import export_prim_to_file
18+
from isaaclab.sim.utils import delete_prim, export_prim_to_file
1919

2020
# import logger
2121
logger = logging.getLogger(__name__)
@@ -173,7 +173,7 @@ def _convert_asset(self, cfg: MeshConverterCfg):
173173
)
174174
# Delete the original prim that will now be a reference
175175
geom_prim_path = geom_prim.GetPath().pathString
176-
omni.kit.commands.execute("DeletePrims", paths=[geom_prim_path], stage=stage)
176+
delete_prim(geom_prim_path, stage=stage)
177177
# Update references to exported Xform and make it instanceable
178178
geom_undef_prim = stage.DefinePrim(geom_prim_path)
179179
geom_undef_prim.GetReferences().AddReference(self.usd_instanceable_meshes_path, primPath=geom_prim_path)
@@ -220,7 +220,6 @@ async def _convert_mesh_to_usd(in_file: str, out_file: str, load_materials: bool
220220
enable_extension("omni.kit.asset_converter")
221221

222222
import omni.kit.asset_converter
223-
import omni.usd
224223

225224
# Create converter context
226225
converter_context = omni.kit.asset_converter.AssetConverterContext()

source/isaaclab/isaaclab/sim/converters/urdf_converter.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
from packaging.version import Version
1111
from typing import TYPE_CHECKING
1212

13-
import isaacsim
1413
import omni.kit.app
1514
import omni.kit.commands
1615

source/isaaclab/isaaclab/sim/spawners/from_files/from_files.py

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@
1717
add_labels,
1818
bind_physics_material,
1919
bind_visual_material,
20+
change_prim_property,
2021
clone,
2122
create_prim,
2223
get_current_stage,
2324
get_first_matching_child_prim,
24-
is_current_stage_in_memory,
2525
select_usd_variants,
2626
set_prim_visibility,
2727
)
@@ -231,25 +231,13 @@ def spawn_ground_plane(
231231
# Change the color of the plane
232232
# Warning: This is specific to the default grid plane asset.
233233
if cfg.color is not None:
234-
# avoiding this step if stage is in memory since the "ChangePropertyCommand" kit command
235-
# is not supported in stage in memory
236-
if is_current_stage_in_memory():
237-
logger.warning(
238-
"Ground plane color modification is not supported while the stage is in memory. Skipping operation."
239-
)
240-
241-
else:
242-
prop_path = f"{prim_path}/Looks/theGrid/Shader.inputs:diffuse_tint"
243-
244-
# change the color
245-
omni.kit.commands.execute(
246-
"ChangePropertyCommand",
247-
prop_path=Sdf.Path(prop_path),
248-
value=Gf.Vec3f(*cfg.color),
249-
prev=None,
250-
type_to_create_if_not_exist=Sdf.ValueTypeNames.Color3f,
251-
usd_context_name=stage,
252-
)
234+
# change the color
235+
change_prim_property(
236+
prop_path=f"{prim_path}/Looks/theGrid/Shader.inputs:diffuse_tint",
237+
value=Gf.Vec3f(*cfg.color),
238+
stage=stage,
239+
type_to_create_if_not_exist=Sdf.ValueTypeNames.Color3f,
240+
)
253241
# Remove the light from the ground plane
254242
# It isn't bright enough and messes up with the user's lighting settings
255243
omni.kit.commands.execute("ToggleVisibilitySelectedPrims", selected_paths=[f"{prim_path}/SphereLight"], stage=stage)

source/isaaclab/isaaclab/sim/spawners/materials/visual_materials.py

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
import logging
99
from typing import TYPE_CHECKING
1010

11-
import omni.kit.commands
12-
from pxr import Usd
11+
from omni.usd.commands import CreateMdlMaterialPrimCommand, CreateShaderPrimFromSdrCommand
12+
from pxr import Usd, UsdShade
1313

14-
from isaaclab.sim.utils import attach_stage_to_usd_context, clone, safe_set_attribute_on_usd_prim
14+
from isaaclab.sim.utils import clone, safe_set_attribute_on_usd_prim
1515
from isaaclab.sim.utils.stage import get_current_stage
1616
from isaaclab.utils.assets import NVIDIA_NUCLEUS_DIR
1717

@@ -30,9 +30,9 @@ def spawn_preview_surface(prim_path: str, cfg: visual_materials_cfg.PreviewSurfa
3030
both *specular* and *metallic* workflows. All color inputs are in linear color space (RGB).
3131
For more information, see the `documentation <https://openusd.org/release/spec_usdpreviewsurface.html>`__.
3232
33-
The function calls the USD command `CreatePreviewSurfaceMaterialPrim`_ to create the prim.
33+
The function calls the USD command `CreateShaderPrimFromSdrCommand`_ to create the prim.
3434
35-
.. _CreatePreviewSurfaceMaterialPrim: https://docs.omniverse.nvidia.com/kit/docs/omni.usd/latest/omni.usd.commands/omni.usd.commands.CreatePreviewSurfaceMaterialPrimCommand.html
35+
.. _CreateShaderPrimFromSdrCommand: https://docs.omniverse.nvidia.com/kit/docs/omni.usd/latest/omni.usd.commands/omni.usd.commands.CreateShaderPrimFromSdrCommand.html
3636
3737
.. note::
3838
This function is decorated with :func:`clone` that resolves prim path into list of paths
@@ -55,18 +55,39 @@ def spawn_preview_surface(prim_path: str, cfg: visual_materials_cfg.PreviewSurfa
5555

5656
# spawn material if it doesn't exist.
5757
if not stage.GetPrimAtPath(prim_path).IsValid():
58-
# early attach stage to usd context if stage is in memory
59-
# since stage in memory is not supported by the "CreatePreviewSurfaceMaterialPrim" kit command
60-
attach_stage_to_usd_context(attaching_early=True)
61-
62-
omni.kit.commands.execute("CreatePreviewSurfaceMaterialPrim", mtl_path=prim_path, select_new_prim=False)
58+
# note: we don't use Omniverse's CreatePreviewSurfaceMaterialPrimCommand
59+
# since it does not support USD stage as an argument. The created material
60+
# in that case is always the one from USD Context which makes it difficult to
61+
# handle scene creation on a custom stage.
62+
material_prim = UsdShade.Material.Define(stage, prim_path)
63+
if material_prim:
64+
shader_prim = CreateShaderPrimFromSdrCommand(
65+
parent_path=prim_path,
66+
identifier="UsdPreviewSurface",
67+
stage_or_context=stage,
68+
name="Shader",
69+
).do()
70+
# bind the shader graph to the material
71+
if shader_prim:
72+
surface_out = shader_prim.GetOutput("surface")
73+
if surface_out:
74+
material_prim.CreateSurfaceOutput().ConnectToSource(surface_out)
75+
76+
displacement_out = shader_prim.GetOutput("displacement")
77+
if displacement_out:
78+
material_prim.CreateDisplacementOutput().ConnectToSource(displacement_out)
79+
else:
80+
raise ValueError(f"Failed to create preview surface shader at path: '{prim_path}'.")
6381
else:
6482
raise ValueError(f"A prim already exists at path: '{prim_path}'.")
6583

6684
# obtain prim
6785
prim = stage.GetPrimAtPath(f"{prim_path}/Shader")
86+
# check prim is valid
87+
if not prim.IsValid():
88+
raise ValueError(f"Failed to create preview surface material at path: '{prim_path}'.")
6889
# apply properties
69-
cfg = cfg.to_dict()
90+
cfg = cfg.to_dict() # type: ignore
7091
del cfg["func"]
7192
for attr_name, attr_value in cfg.items():
7293
safe_set_attribute_on_usd_prim(prim, f"inputs:{attr_name}", attr_value, camel_case=True)
@@ -75,7 +96,9 @@ def spawn_preview_surface(prim_path: str, cfg: visual_materials_cfg.PreviewSurfa
7596

7697

7798
@clone
78-
def spawn_from_mdl_file(prim_path: str, cfg: visual_materials_cfg.MdlMaterialCfg) -> Usd.Prim:
99+
def spawn_from_mdl_file(
100+
prim_path: str, cfg: visual_materials_cfg.MdlFileCfg | visual_materials_cfg.GlassMdlCfg
101+
) -> Usd.Prim:
79102
"""Load a material from its MDL file and override the settings with the given config.
80103
81104
NVIDIA's `Material Definition Language (MDL) <https://www.nvidia.com/en-us/design-visualization/technologies/material-definition-language/>`__
@@ -108,25 +131,24 @@ def spawn_from_mdl_file(prim_path: str, cfg: visual_materials_cfg.MdlMaterialCfg
108131

109132
# spawn material if it doesn't exist.
110133
if not stage.GetPrimAtPath(prim_path).IsValid():
111-
# early attach stage to usd context if stage is in memory
112-
# since stage in memory is not supported by the "CreateMdlMaterialPrim" kit command
113-
attach_stage_to_usd_context(attaching_early=True)
114-
115134
# extract material name from path
116135
material_name = cfg.mdl_path.split("/")[-1].split(".")[0]
117-
omni.kit.commands.execute(
118-
"CreateMdlMaterialPrim",
136+
CreateMdlMaterialPrimCommand(
119137
mtl_url=cfg.mdl_path.format(NVIDIA_NUCLEUS_DIR=NVIDIA_NUCLEUS_DIR),
120138
mtl_name=material_name,
121139
mtl_path=prim_path,
140+
stage=stage,
122141
select_new_prim=False,
123-
)
142+
).do()
124143
else:
125144
raise ValueError(f"A prim already exists at path: '{prim_path}'.")
126145
# obtain prim
127146
prim = stage.GetPrimAtPath(f"{prim_path}/Shader")
147+
# check prim is valid
148+
if not prim.IsValid():
149+
raise ValueError(f"Failed to create MDL material at path: '{prim_path}'.")
128150
# apply properties
129-
cfg = cfg.to_dict()
151+
cfg = cfg.to_dict() # type: ignore
130152
del cfg["func"]
131153
del cfg["mdl_path"]
132154
for attr_name, attr_value in cfg.items():

source/isaaclab/isaaclab/sim/spawners/sensors/sensors.py

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,9 @@
88
import logging
99
from typing import TYPE_CHECKING
1010

11-
import omni.kit.commands
1211
from pxr import Sdf, Usd
1312

14-
from isaaclab.sim.utils import attach_stage_to_usd_context, clone, create_prim, get_current_stage
13+
from isaaclab.sim.utils import change_prim_property, clone, create_prim, get_current_stage
1514
from isaaclab.utils import to_camel_case
1615

1716
if TYPE_CHECKING:
@@ -94,17 +93,11 @@ def spawn_camera(
9493

9594
# lock camera from viewport (this disables viewport movement for camera)
9695
if cfg.lock_camera:
97-
# early attach stage to usd context if stage is in memory
98-
# since stage in memory is not supported by the "ChangePropertyCommand" kit command
99-
attach_stage_to_usd_context(attaching_early=True)
100-
101-
omni.kit.commands.execute(
102-
"ChangePropertyCommand",
103-
prop_path=Sdf.Path(f"{prim_path}.omni:kit:cameraLock"),
96+
change_prim_property(
97+
prop_path=f"{prim_path}.omni:kit:cameraLock",
10498
value=True,
105-
prev=None,
99+
stage=stage,
106100
type_to_create_if_not_exist=Sdf.ValueTypeNames.Bool,
107-
usd_context_name=stage,
108101
)
109102
# decide the custom attributes to add
110103
if cfg.projection_type == "pinhole":

0 commit comments

Comments
 (0)