From 55dedc29ce17e8dfc6d0a550e9cec2c14a6609fc Mon Sep 17 00:00:00 2001 From: Xinjie Date: Thu, 30 Oct 2025 20:00:32 +0800 Subject: [PATCH] feat(conversion): Add `cvt_embodiedgen_asset_to_anysim` interface. (#48) --- embodied_gen/data/asset_converter.py | 109 ++++++++++++++++++++++++--- 1 file changed, 100 insertions(+), 9 deletions(-) diff --git a/embodied_gen/data/asset_converter.py b/embodied_gen/data/asset_converter.py index 546a75b..5214fec 100644 --- a/embodied_gen/data/asset_converter.py +++ b/embodied_gen/data/asset_converter.py @@ -21,6 +21,9 @@ __all__ = [ "MeshtoMJCFConverter", "MeshtoUSDConverter", "URDFtoUSDConverter", + "cvt_embodiedgen_asset_to_anysim", + "PhysicsUSDAdder", + "SimAssetMapper", ] @@ -34,6 +37,84 @@ class AssetType(str): MESH = "mesh" +class SimAssetMapper: + _mapping = dict( + ISAACSIM=AssetType.USD, + ISAACGYM=AssetType.URDF, + MUJOCO=AssetType.MJCF, + GENESIS=AssetType.MJCF, + SAPIEN=AssetType.URDF, + PYBULLET=AssetType.URDF, + ) + + @classmethod + def __class_getitem__(cls, key: str): + key = key.upper() + if key.startswith("SAPIEN"): + key = "SAPIEN" + return cls._mapping[key] + + +def cvt_embodiedgen_asset_to_anysim( + urdf_files: list[str], + target_type: AssetType, + source_type: AssetType, + **kwargs, +) -> dict[str, str]: + """Convert URDF files generated by EmbodiedGen into the format required by all simulators. + + Supported simulators include SAPIEN, Isaac Sim, MuJoCo, Isaac Gym, Genesis, and Pybullet. + + Example: + dst_asset_path = cvt_embodiedgen_asset_to_anysim( + urdf_files, + target_type=SimAssetMapper[simulator_name], + source_type=AssetType.MESH, + ) + + Args: + urdf_files (List[str]): List of URDF file paths to be converted. + target_type (AssetType): The target asset type. + source_type (AssetType): The source asset type. + + Returns: + Dict[str, str]: A dictionary mapping the original URDF file path to the converted asset file path. + """ + + if isinstance(urdf_files, str): + urdf_files = [urdf_files] + + # If the target type is URDF, no conversion is needed. + if target_type == AssetType.URDF: + return {key: key for key in urdf_files} + + asset_converter = AssetConverterFactory.create( + target_type=target_type, + source_type=source_type, + **kwargs, + ) + asset_paths = dict() + + with asset_converter: + for urdf_file in urdf_files: + filename = os.path.basename(urdf_file).replace(".urdf", "") + asset_dir = os.path.dirname(urdf_file) + if target_type == AssetType.MJCF: + target_file = f"{asset_dir}/../mjcf/{filename}.xml" + elif target_type == AssetType.USD: + target_file = f"{asset_dir}/../usd/{filename}.usd" + else: + raise NotImplementedError( + f"Target type {target_type} not supported." + ) + if not os.path.exists(target_file): + asset_converter.convert(urdf_file, target_file) + + asset_paths[urdf_file] = target_file + + return asset_paths + + class AssetConverterBase(ABC): """Converter abstract base class.""" @@ -222,6 +303,7 @@ class MeshtoMJCFConverter(AssetConverterBase): output_dir, name=str(idx), ) + joint = ET.SubElement(body, "joint", attrib={"type": "free"}) self.add_geometry( mujoco_asset, link, @@ -357,24 +439,33 @@ class MeshtoUSDConverter(AssetConverterBase): simulation_app=None, **kwargs, ): + if simulation_app is not None: + self.simulation_app = simulation_app + + if "exit_close" in kwargs: + self.exit_close = kwargs.pop("exit_close") + else: + self.exit_close = True + self.usd_parms = dict( force_usd_conversion=force_usd_conversion, make_instanceable=make_instanceable, **kwargs, ) - if simulation_app is not None: - self.simulation_app = simulation_app def __enter__(self): from isaaclab.app import AppLauncher if not hasattr(self, "simulation_app"): - launch_args = dict( - headless=True, - no_splash=True, - fast_shutdown=True, - disable_gpu=True, - ) + if "launch_args" not in self.usd_parms: + launch_args = dict( + headless=True, + no_splash=True, + fast_shutdown=True, + disable_gpu=True, + ) + else: + launch_args = self.usd_parms.pop("launch_args") self.app_launcher = AppLauncher(launch_args) self.simulation_app = self.app_launcher.app @@ -382,7 +473,7 @@ class MeshtoUSDConverter(AssetConverterBase): def __exit__(self, exc_type, exc_val, exc_tb): # Close the simulation app if it was created here - if hasattr(self, "app_launcher"): + if hasattr(self, "app_launcher") and self.exit_close: self.simulation_app.close() if exc_val is not None: