Unverified Commit a9b5df11 authored by Mayank Mittal's avatar Mayank Mittal Committed by GitHub

Fixes absolute paths in instanceable meshes with URDF Converter (#225)

# Description

With at least Isaac Sim 2023.1 (not checked on 2022.2.1), the URDF
importer from Isaac Sim seems to save the material paths as absolute
when trying to save the asset in its instanceable format. The material
paths are relative when the USD is generated as non-instanceable.

This MR fixes this behavior by adding a post-processing step that
iterates over the instanced mesh file and resolves all paths to become
relative.

You can use the tool by running the following:

```bash
./orbit.sh -p source/tools/convert_urdf.py ~/git/anymal_d_simple_description/urdf/anymal.urdf source/extensions/omni.isaac.orbit_assets/data/Robots/ANYbotics/ANYmalD/anymal_instanceable.usda --merge-joints --make-instanceable
```

## Type of change

- Bug fix (non-breaking change which fixes an issue)
- New feature (non-breaking change which adds functionality)

## Checklist

- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./orbit.sh --format`
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
parent 72035785
[package] [package]
# Note: Semantic Versioning is used: https://semver.org/ # Note: Semantic Versioning is used: https://semver.org/
version = "0.9.28" version = "0.9.29"
# Description # Description
title = "ORBIT framework for Robot Learning" title = "ORBIT framework for Robot Learning"
......
Changelog Changelog
--------- ---------
0.9.29 (2023-11-01)
~~~~~~~~~~~~~~~~~~~
Fixed
^^^^^
* Fixed the material path resolution inside the :class:`omni.isaac.orbit.sim.converters.UrdfConverter` class.
With Isaac Sim 2023.1, the material paths from the importer are always saved as absolute paths. This caused
issues when the generated USD file was moved to a different location. The fix now resolves the material paths
relative to the USD file location.
0.9.28 (2023-11-01) 0.9.28 (2023-11-01)
~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~
......
...@@ -78,7 +78,7 @@ class AssetConverterBase(abc.ABC): ...@@ -78,7 +78,7 @@ class AssetConverterBase(abc.ABC):
usd_file_name = cfg.usd_file_name usd_file_name = cfg.usd_file_name
# add USD extension if not provided # add USD extension if not provided
if not (usd_file_name.endswith(".usd") or usd_file_name.endswith(".usda")): if not (usd_file_name.endswith(".usd") or usd_file_name.endswith(".usda")):
self._usd_file_name = usd_file_name + ".usda" self._usd_file_name = usd_file_name + ".usd"
else: else:
self._usd_file_name = usd_file_name self._usd_file_name = usd_file_name
...@@ -107,6 +107,14 @@ class AssetConverterBase(abc.ABC): ...@@ -107,6 +107,14 @@ class AssetConverterBase(abc.ABC):
self._convert_asset(cfg) self._convert_asset(cfg)
# dump the configuration to a file # dump the configuration to a file
dump_yaml(os.path.join(self.usd_dir, "config.yaml"), cfg.to_dict()) dump_yaml(os.path.join(self.usd_dir, "config.yaml"), cfg.to_dict())
# add comment to top of the saved config file with information about the converter
current_date = datetime.now().strftime("%Y-%m-%d")
current_time = datetime.now().strftime("%H:%M:%S")
generation_comment = (
f"##\n# Generated by {self.__class__.__name__} on {current_date} at {current_time}.\n##\n"
)
with open(os.path.join(self.usd_dir, "config.yaml"), "a") as f:
f.write(generation_comment)
""" """
Properties. Properties.
...@@ -135,7 +143,7 @@ class AssetConverterBase(abc.ABC): ...@@ -135,7 +143,7 @@ class AssetConverterBase(abc.ABC):
mesh references in the generated USD file are resolved relatively. Otherwise, it becomes mesh references in the generated USD file are resolved relatively. Otherwise, it becomes
difficult to move the USD asset to a different location. difficult to move the USD asset to a different location.
""" """
return os.path.join(".", "Props", "instanceable_meshes.usda") return os.path.join(".", "Props", "instanceable_meshes.usd")
""" """
Implementation specifics. Implementation specifics.
......
...@@ -28,8 +28,11 @@ class AssetConverterBaseCfg: ...@@ -28,8 +28,11 @@ class AssetConverterBaseCfg:
usd_file_name: str | None = None usd_file_name: str | None = None
"""The name of the generated usd file. Defaults to :obj:`None`. """The name of the generated usd file. Defaults to :obj:`None`.
If set to :obj:`None`, it is resolved from the asset file name. The extension of the asset file If set to :obj:`None`, it is resolved from the asset file name. For example, if the asset file
is replaced with ``.usd``. name is ``"my_asset.urdf"``, then the generated USD file name is ``"my_asset.usd"``.
If the providing file name does not end with ".usd" or ".usda", then the extension
".usd" is appended to the file name.
""" """
force_usd_conversion: bool = False force_usd_conversion: bool = False
......
...@@ -6,9 +6,13 @@ ...@@ -6,9 +6,13 @@
from __future__ import annotations from __future__ import annotations
import os
import omni.kit.commands import omni.kit.commands
import omni.usd
from omni.isaac.core.utils.extensions import enable_extension from omni.isaac.core.utils.extensions import enable_extension
from omni.isaac.version import get_version from omni.isaac.version import get_version
from pxr import Usd
from .asset_converter_base import AssetConverterBase from .asset_converter_base import AssetConverterBase
from .urdf_converter_cfg import UrdfConverterCfg from .urdf_converter_cfg import UrdfConverterCfg
...@@ -81,6 +85,14 @@ class UrdfConverter(AssetConverterBase): ...@@ -81,6 +85,14 @@ class UrdfConverter(AssetConverterBase):
import_config=import_config, import_config=import_config,
dest_path=self.usd_path, dest_path=self.usd_path,
) )
# fix the issue that material paths are not relative
if self.cfg.make_instanceable:
usd_path = os.path.join(self.usd_dir, self.usd_instanceable_meshes_path)
stage = Usd.Stage.Open(usd_path)
# resolve all paths relative to layer path
source_layer = stage.GetRootLayer()
omni.usd.resolve_paths(source_layer.identifier, source_layer.identifier)
stage.Save()
""" """
Helper methods. Helper methods.
......
...@@ -20,11 +20,11 @@ positional arguments: ...@@ -20,11 +20,11 @@ positional arguments:
output The path to store the USD file. output The path to store the USD file.
optional arguments: optional arguments:
-h, --help Show this help message and exit -h, --help Show this help message and exit
--headless Force display off at all times. (default: False) --headless Force display off at all times. (default: False)
--merge-joints, -m Consolidate links that are connected by fixed joints. (default: False) --merge-joints, -m Consolidate links that are connected by fixed joints. (default: False)
--fix-base, -f Fix the base to where it is imported. (default: False) --fix-base, -f Fix the base to where it is imported. (default: False)
--make-instanced, -i Make the asset instanceable for efficient cloning. (default: False) --make-instanceable, -i Make the asset instanceable for efficient cloning. (default: False)
""" """
...@@ -55,7 +55,7 @@ parser.add_argument( ...@@ -55,7 +55,7 @@ parser.add_argument(
"--fix-base", "-f", action="store_true", default=False, help="Fix the base to where it is imported." "--fix-base", "-f", action="store_true", default=False, help="Fix the base to where it is imported."
) )
parser.add_argument( parser.add_argument(
"--make-instanced", "--make-instanceable",
"-i", "-i",
action="store_true", action="store_true",
default=False, default=False,
...@@ -102,7 +102,7 @@ def main(): ...@@ -102,7 +102,7 @@ def main():
fix_base=args_cli.fix_base, fix_base=args_cli.fix_base,
merge_fixed_joints=args_cli.merge_joints, merge_fixed_joints=args_cli.merge_joints,
force_usd_conversion=True, force_usd_conversion=True,
make_instanceable=args_cli.make_instanced, make_instanceable=args_cli.make_instanceable,
) )
# Print info # Print info
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment