Skip to content

Commit 8536091

Browse files
hujc7isaaclab-bot[bot]
authored andcommitted
Keep search-path asset identifiers intact when resolving layer paths (#7484)
# Description `resolve_paths` passed the result of `Sdf.Layer.ComputeAbsolutePath` straight to `os.path.relpath`. USD returns *search-path* identifiers unchanged, so a non-absolute string such as the MDL module `OmniPBR.mdl` was anchored at the process working directory instead of the layer's location. `MeshConverter` routes every `--make-instanceable` export through this helper, so each MDL material in `Props/instanceable_meshes.usd` pointed at a module that does not exist. Fixes NVBug 6675386, NVBug 6703374 ## 1. Before / after Converting `cube_multicolor.obj` with `--make-instanceable`, output under `source/isaaclab_assets/data/Props/CubeMultiColor/`: | | `info:mdl:sourceAsset` in `Props/instanceable_meshes.usd` | | --- | --- | | Before | `@../../../../../../OmniPBR.mdl@` (six levels up = the process CWD) | | After | `@OmniPBR.mdl@` | The renderer then logged `MDLC comp error: C120 could not find module '::..::..::..::..::..::..::OmniPBR'` and `Unable to find SdrShaderNode` once per material. ## 2. Verified QA's exact command (`--make-instanceable --collision-approximation convexDecomposition --mass 1.0 --visualizer kit,viser,rerun,newton_gl`), before and after, on the build the reports were filed against: | Isaac Sim | `MDLC comp error: C120` | `Unable to find SdrShaderNode` | | --- | --- | --- | | 6.1.0rc17 (Kit 110.3.0+feature.370106), before | 1 | 6 | | 6.1.0rc17, after | 0 | 0 | | 6.0.0-rc.59 (Kit 110.1.1), before | 1 | 6 | | 6.0.0-rc.59, after | 0 | 0 | The added unit test fails on `develop` (`@../../../workspace/isaaclab/OmniPBR.mdl@`) and passes with the fix. ## 3. Design notes Only paths that `ComputeAbsolutePath` actually resolved to an absolute location are re-anchored; anything else is returned as authored, for the renderer's module path to resolve. Genuine relative references still move with the layer — the added test asserts `@../meshes/mesh.usda@` alongside the untouched `@OmniPBR.mdl@`. ## Type of change - Bug fix (non-breaking change which fixes an issue) ## Release backport - [x] <!-- backport-active-release --> Backport this pull request to the active release branch after it merges into `develop` ## 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` - [x] 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 - [x] I have added a changelog fragment under `source/<pkg>/changelog.d/` for every touched package - [x] I have added my name to the `CONTRIBUTORS.md` or my name already exists there (cherry picked from commit d592423)
1 parent 21a2e7c commit 8536091

3 files changed

Lines changed: 57 additions & 2 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Fixed
2+
^^^^^
3+
4+
* Fixed :func:`~isaaclab.sim.utils.resolve_paths` rewriting search-path asset identifiers, such as
5+
the MDL module ``OmniPBR.mdl``, into paths relative to the process working directory. Assets
6+
converted with ``--make-instanceable`` referenced a non-existent MDL module, so the renderer
7+
logged ``MDLC comp error: C120 could not find module`` and left their materials unresolved.

source/isaaclab/isaaclab/sim/utils/stage.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,17 @@ def _modify_path(asset_path: str) -> str:
121121
resolved = src_layer.ComputeAbsolutePath(asset_path)
122122
if resolved and _is_uri_path(resolved):
123123
return resolved
124-
if store_relative_path and resolved and dst_dir:
124+
# Search-path identifiers (e.g. the MDL module ``OmniPBR.mdl``) come back unchanged: they
125+
# are resolved against the renderer's module path, not the layer's directory. Re-anchoring
126+
# one would make it relative to the process working directory and point at nothing.
127+
if not os.path.isabs(resolved):
128+
return asset_path
129+
if store_relative_path and dst_dir:
125130
try:
126131
return os.path.relpath(resolved, dst_dir)
127132
except ValueError:
128133
return resolved
129-
return resolved or asset_path
134+
return resolved
130135

131136
UsdUtils.ModifyAssetPaths(dst_layer, _modify_path)
132137

source/isaaclab/test/sim/test_utils_stage.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,49 @@ def test_resolve_paths():
321321
assert cube_prim.GetTypeName() == "Cube"
322322

323323

324+
def test_resolve_paths_keeps_search_path_assets():
325+
"""Test resolve_paths leaves search-path asset identifiers untouched.
326+
327+
Identifiers such as the MDL module ``OmniPBR.mdl`` are resolved against the renderer's module
328+
path rather than the layer's directory, so re-anchoring one to the destination layer yields a
329+
path relative to the process working directory that resolves to nothing.
330+
"""
331+
from pxr import Sdf, UsdShade
332+
333+
from isaaclab.sim.utils.stage import resolve_paths
334+
335+
with tempfile.TemporaryDirectory() as temp_dir:
336+
# Create a mesh the source asset references through a directory-qualified relative path
337+
mesh_path = Path(temp_dir) / "meshes" / "mesh.usda"
338+
mesh_path.parent.mkdir(parents=True, exist_ok=True)
339+
mesh_stage = Usd.Stage.CreateNew(str(mesh_path))
340+
mesh_stage.GetRootLayer().Save()
341+
342+
# Create the source asset with a mesh reference and an MDL shader
343+
source_path = Path(temp_dir) / "asset.usda"
344+
source_stage = Usd.Stage.CreateNew(str(source_path))
345+
world_prim = source_stage.DefinePrim("/World", "Xform")
346+
world_prim.GetReferences().AddReference("./meshes/mesh.usda")
347+
shader = UsdShade.Shader.Define(source_stage, "/World/Looks/red/red")
348+
shader.SetSourceAsset(Sdf.AssetPath("OmniPBR.mdl"), "mdl")
349+
source_stage.GetRootLayer().Save()
350+
351+
# Copy the layer one directory deeper, as export_prim_to_file does for instanceable meshes
352+
dest_path = Path(temp_dir) / "Props" / "instanceable_meshes.usda"
353+
dest_path.parent.mkdir(parents=True, exist_ok=True)
354+
dest_layer = Sdf.Layer.CreateNew(str(dest_path))
355+
dest_layer.TransferContent(source_stage.GetRootLayer())
356+
357+
resolve_paths(str(source_path), str(dest_path))
358+
dest_layer.Save()
359+
360+
contents = dest_layer.ExportToString()
361+
# the MDL module keeps its search-path identifier
362+
assert "@OmniPBR.mdl@" in contents
363+
# the mesh reference is re-anchored to the new location
364+
assert "@../meshes/mesh.usda@" in contents
365+
366+
324367
def test_stage_context_tracking():
325368
"""Test that stage context is properly tracked across operations."""
326369
# Create initial stage

0 commit comments

Comments
 (0)