Skip to content

Collision Mesh Schema Additions #2249

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Guidelines for modifications:
* Gary Lvov
* Giulio Romualdi
* Haoran Zhou
* Harsh Patel
* HoJin Jeon
* Hongwei Xiong
* Hongyu Li
Expand Down
9 changes: 5 additions & 4 deletions source/isaaclab/isaaclab/sim/converters/mesh_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,14 +122,15 @@ def _convert_asset(self, cfg: MeshConverterCfg):
if child_mesh_prim.GetTypeName() == "Mesh":
# Apply collider properties to mesh
if cfg.collision_props is not None:
# -- Collision approximation to mesh
# TODO: Move this to a new Schema: https://github.com/isaac-orbit/IsaacLab/issues/163
mesh_collision_api = UsdPhysics.MeshCollisionAPI.Apply(child_mesh_prim)
mesh_collision_api.GetApproximationAttr().Set(cfg.collision_approximation)
# -- Collider properties such as offset, scale, etc.
schemas.define_collision_properties(
prim_path=child_mesh_prim.GetPath(), cfg=cfg.collision_props, stage=stage
)
# Add collision mesh
if cfg.mesh_collision_props is not None:
schemas.define_mesh_collision_properties(
prim_path=child_mesh_prim.GetPath(), cfg=cfg.mesh_collision_props, stage=stage
)
# Delete the old Xform and make the new Xform the default prim
stage.SetDefaultPrim(xform_prim)
# Apply default Xform rotation to mesh -> enable to set rotation and scale
Expand Down
19 changes: 7 additions & 12 deletions source/isaaclab/isaaclab/sim/converters/mesh_converter_cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,35 +12,30 @@
class MeshConverterCfg(AssetConverterBaseCfg):
"""The configuration class for MeshConverter."""

mass_props: schemas_cfg.MassPropertiesCfg | None = None
mass_props: schemas_cfg.MassPropertiesCfg = None
"""Mass properties to apply to the USD. Defaults to None.

Note:
If None, then no mass properties will be added.
"""

rigid_props: schemas_cfg.RigidBodyPropertiesCfg | None = None
rigid_props: schemas_cfg.RigidBodyPropertiesCfg = None
"""Rigid body properties to apply to the USD. Defaults to None.

Note:
If None, then no rigid body properties will be added.
"""

collision_props: schemas_cfg.CollisionPropertiesCfg | None = None
collision_props: schemas_cfg.CollisionPropertiesCfg = None
"""Collision properties to apply to the USD. Defaults to None.

Note:
If None, then no collision properties will be added.
"""

collision_approximation: str = "convexDecomposition"
"""Collision approximation method to use. Defaults to "convexDecomposition".

Valid options are:
"convexDecomposition", "convexHull", "boundingCube",
"boundingSphere", "meshSimplification", or "none"

"none" causes no collision mesh to be added.
mesh_collision_props: schemas_cfg.MeshCollisionPropertiesCfg = None
"""Mesh approximation properties to apply to all collision meshes in the USD.
Note:
If None, then no mesh approximation properties will be added.
"""

translation: tuple[float, float, float] = (0.0, 0.0, 0.0)
Expand Down
53 changes: 53 additions & 0 deletions source/isaaclab/isaaclab/sim/schemas/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,26 +33,79 @@
"""

from .schemas import (
PHYSX_MESH_COLLISION_CFGS,
USD_MESH_COLLISION_CFGS,
activate_contact_sensors,
define_articulation_root_properties,
define_collision_properties,
define_deformable_body_properties,
define_mass_properties,
define_mesh_collision_properties,
define_rigid_body_properties,
modify_articulation_root_properties,
modify_collision_properties,
modify_deformable_body_properties,
modify_fixed_tendon_properties,
modify_joint_drive_properties,
modify_mass_properties,
modify_mesh_collision_properties,
modify_rigid_body_properties,
)
from .schemas_cfg import (
ArticulationRootPropertiesCfg,
BoundingCubePropertiesCfg,
BoundingSpherePropertiesCfg,
CollisionPropertiesCfg,
ConvexDecompositionPropertiesCfg,
ConvexHullPropertiesCfg,
DeformableBodyPropertiesCfg,
FixedTendonPropertiesCfg,
JointDrivePropertiesCfg,
MassPropertiesCfg,
MeshCollisionPropertiesCfg,
RigidBodyPropertiesCfg,
SDFMeshPropertiesCfg,
TriangleMeshPropertiesCfg,
TriangleMeshSimplificationPropertiesCfg,
)

__all__ = [
# articulation root
"ArticulationRootPropertiesCfg",
"define_articulation_root_properties",
"modify_articulation_root_properties",
# rigid bodies
"RigidBodyPropertiesCfg",
"define_rigid_body_properties",
"modify_rigid_body_properties",
"activate_contact_sensors",
# colliders
"CollisionPropertiesCfg",
"define_collision_properties",
"modify_collision_properties",
# mass
"MassPropertiesCfg",
"define_mass_properties",
"modify_mass_properties",
# mesh colliders
"MeshCollisionPropertiesCfg",
"define_mesh_collision_properties",
"modify_mesh_collision_properties",
# bounding cube
"BoundingCubePropertiesCfg",
# bounding sphere
"BoundingSpherePropertiesCfg",
# convex decomposition
"ConvexDecompositionPropertiesCfg",
# convex hull
"ConvexHullPropertiesCfg",
# sdf mesh
"SDFMeshPropertiesCfg",
# triangle mesh
"TriangleMeshPropertiesCfg",
# triangle mesh simplification
"TriangleMeshSimplificationPropertiesCfg",
# Constants for configs that use PhysX vs USD API
"PHYSX_MESH_COLLISION_CFGS",
"USD_MESH_COLLISION_CFGS",
]
134 changes: 134 additions & 0 deletions source/isaaclab/isaaclab/sim/schemas/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,22 @@
Articulation root properties.
"""

PHYSX_MESH_COLLISION_CFGS = [
schemas_cfg.ConvexDecompositionPropertiesCfg,
schemas_cfg.ConvexHullPropertiesCfg,
schemas_cfg.TriangleMeshPropertiesCfg,
schemas_cfg.TriangleMeshSimplificationPropertiesCfg,
schemas_cfg.SDFMeshPropertiesCfg,
]

USD_MESH_COLLISION_CFGS = [
schemas_cfg.BoundingCubePropertiesCfg,
schemas_cfg.BoundingSpherePropertiesCfg,
schemas_cfg.ConvexDecompositionPropertiesCfg,
schemas_cfg.ConvexHullPropertiesCfg,
schemas_cfg.TriangleMeshSimplificationPropertiesCfg,
]


def define_articulation_root_properties(
prim_path: str, cfg: schemas_cfg.ArticulationRootPropertiesCfg, stage: Usd.Stage | None = None
Expand Down Expand Up @@ -851,3 +867,121 @@ def modify_deformable_body_properties(

# success
return True


"""
Collision mesh properties.
"""


def extract_mesh_collision_api_and_attrs(cfg):
# We use the number of user set attributes outside of the API function
# to determine which API to use in ambiguous cases, so collect them here
custom_attrs = {
key: value
for key, value in cfg.to_dict().items()
if value is not None and key not in ["usd_func", "physx_func"]
}

use_usd_api = False
use_phsyx_api = False

# We have some custom attributes and allow them
if len(custom_attrs) > 0 and type(cfg) in PHYSX_MESH_COLLISION_CFGS:
use_phsyx_api = True
# We have no custom attributes
elif len(custom_attrs) == 0:
if type(cfg) in USD_MESH_COLLISION_CFGS:
# Use the USD API
use_usd_api = True
else:
# Use the PhysX API
use_phsyx_api = True

elif len(custom_attrs > 0) and type(cfg) in USD_MESH_COLLISION_CFGS:
raise ValueError("Args are specified but the USD Mesh API doesn't support them!")

mesh_collision_appx_type = type(cfg).__name__.partition("PropertiesCfg")[0]

if use_usd_api:
# Add approximation to the attributes as this is how USD collision mesh API is configured
api_func = cfg.usd_func
# Approximation needs to be formatted with camelCase
custom_attrs["Approximation"] = mesh_collision_appx_type[0].lower() + mesh_collision_appx_type[1:]
elif use_phsyx_api:
api_func = cfg.physx_func
else:
raise ValueError("Either USD or PhysX API should be used for mesh collision approximation!")

return api_func, custom_attrs


def define_mesh_collision_properties(
prim_path: str, cfg: schemas_cfg.MeshCollisionPropertiesCfg, stage: Usd.Stage | None = None
):
"""Apply the mesh collision schema on the input prim and set its properties.
See :func:`modify_collision_mesh_properties` for more details on how the properties are set.
Args:
prim_path : The prim path where to apply the mesh collision schema.
cfg : The configuration for the mesh collision properties.
stage : The stage where to find the prim. Defaults to None, in which case the
current stage is used.
Raises:
ValueError: When the prim path is not valid.
"""
# obtain stage
if stage is None:
stage = stage_utils.get_current_stage()
# get USD prim
prim = stage.GetPrimAtPath(prim_path)
# check if prim path is valid
if not prim.IsValid():
raise ValueError(f"Prim path '{prim_path}' is not valid.")

api_func, _ = extract_mesh_collision_api_and_attrs(cfg=cfg)

# Only enable if not already enabled
if not api_func(prim):
api_func.Apply(prim)

modify_mesh_collision_properties(prim_path=prim_path, cfg=cfg, stage=stage)


@apply_nested
def modify_mesh_collision_properties(
prim_path: str, cfg: schemas_cfg.MeshCollisionPropertiesCfg, stage: Usd.Stage | None = None
):
"""Set properties for the mesh collision of a prim.
These properties are based on either the `Phsyx the `UsdPhysics.MeshCollisionAPI` schema.
.. note::
This function is decorated with :func:`apply_nested` that sets the properties to all the prims
(that have the schema applied on them) under the input prim path.
.. UsdPhysics.MeshCollisionAPI: https://openusd.org/release/api/class_usd_physics_mesh_collision_a_p_i.html
Args:
prim_path : The prim path of the rigid body. This prim should be a Mesh prim.
cfg : The configuration for the mesh collision properties.
stage : The stage where to find the prim. Defaults to None, in which case the
current stage is used.
"""
# obtain stage
if stage is None:
stage = stage_utils.get_current_stage()
# get USD prim
prim = stage.GetPrimAtPath(prim_path)

api_func, custom_attrs = extract_mesh_collision_api_and_attrs(cfg=cfg)

# retrieve the mesh collision API
mesh_collision_api = api_func(prim)

# set custom attributes into mesh collision API
for attr_name, value in custom_attrs.items():
# Only "Attribute" attr should be in format "boundingSphere", so set camel_case to be False
if attr_name == "Attribute":
camel_case = False
else:
camel_case = True
safe_set_attribute_on_usd_schema(mesh_collision_api, attr_name, value, camel_case=camel_case)

# success
return True
Loading