Source code for isaaclab_physx.sim.schemas.schemas

# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause

# needed to import for allowing type-hinting: Usd.Stage | None
from __future__ import annotations

import logging

from omni.physx.scripts import deformableUtils
from pxr import Usd

from isaaclab.sim.utils import (
    apply_nested,
    get_all_matching_child_prims,
    safe_set_attribute_on_usd_prim,
)
from isaaclab.sim.utils.stage import get_current_stage
from isaaclab.utils.string import to_camel_case

from isaaclab_physx.sim.schemas.schemas_cfg import DeformableBodyPropertiesCfg

# import logger
logger = logging.getLogger(__name__)


"""
Deformable body properties.
"""


[docs] def define_deformable_body_properties( prim_path: str, cfg: DeformableBodyPropertiesCfg, stage: Usd.Stage | None = None, deformable_type: str = "volume", sim_mesh_prim_path: str | None = None, ): """Apply the deformable body schema on the input prim and set its properties. See :func:`modify_deformable_body_properties` for more details on how the properties are set. .. note:: If the input prim is not a mesh, this function will traverse the prim and find the first mesh under it. If no mesh or multiple meshes are found, an error is raised. This is because the deformable body schema can only be applied to a single mesh. Args: prim_path: The prim path where to apply the deformable body schema. cfg: The configuration for the deformable body. stage: The stage where to find the prim. Defaults to None, in which case the current stage is used. deformable_type: The type of the deformable body (surface or volume). This is used to determine which PhysX API to use for the deformable body. Defaults to "volume". sim_mesh_prim_path: Optional override for the simulation mesh prim path. If None, it is set to ``{prim_path}/sim_mesh`` for surface deformables and ``{prim_path}/sim_tetmesh`` for volume deformables. Raises: ValueError: When the prim path is not valid. ValueError: When the prim has no mesh or multiple meshes. RuntimeError: When setting the deformable body properties fails. """ # get stage handle if stage is None: stage = 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.") # traverse the prim and get the mesh. If none or multiple meshes are found, raise error. matching_prims = get_all_matching_child_prims(prim_path, lambda p: p.GetTypeName() == "Mesh") # check if the volume deformable mesh is valid if len(matching_prims) == 0: raise ValueError(f"Could not find any mesh in '{prim_path}'. Please check asset.") if len(matching_prims) > 1: # get list of all meshes found mesh_paths = [p.GetPrimPath() for p in matching_prims] raise ValueError( f"Found multiple meshes in '{prim_path}': {mesh_paths}." " Deformable body schema can only be applied to one mesh." ) mesh_prim = matching_prims[0] mesh_prim_path = mesh_prim.GetPrimPath() # check if the prim is valid if not mesh_prim.IsValid(): raise ValueError(f"Mesh prim path '{mesh_prim_path}' is not valid.") # set root prim properties based on the type of the deformable mesh (surface vs volume) if deformable_type == "surface": sim_mesh_prim_path = prim_path + "/sim_mesh" if sim_mesh_prim_path is None else sim_mesh_prim_path success = deformableUtils.create_auto_surface_deformable_hierarchy( stage=stage, root_prim_path=prim_path, simulation_mesh_path=sim_mesh_prim_path, cooking_src_mesh_path=mesh_prim_path, cooking_src_simplification_enabled=False, set_visibility_with_guide_purpose=True, ) elif deformable_type == "volume": sim_mesh_prim_path = prim_path + "/sim_tetmesh" if sim_mesh_prim_path is None else sim_mesh_prim_path success = deformableUtils.create_auto_volume_deformable_hierarchy( stage=stage, root_prim_path=prim_path, simulation_tetmesh_path=sim_mesh_prim_path, collision_tetmesh_path=sim_mesh_prim_path, cooking_src_mesh_path=mesh_prim_path, simulation_hex_mesh_enabled=False, cooking_src_simplification_enabled=False, set_visibility_with_guide_purpose=True, ) else: raise ValueError( f"""Unsupported deformable type: '{deformable_type}'. Only surface and volume deformables are supported.""" ) # api failure if not success: raise RuntimeError(f"Failed to set deformable body properties on prim '{mesh_prim_path}'.") # set deformable body properties modify_deformable_body_properties(prim_path, cfg, stage)
[docs] @apply_nested def modify_deformable_body_properties(prim_path: str, cfg: DeformableBodyPropertiesCfg, stage: Usd.Stage | None = None): """Modify PhysX parameters for a deformable body prim. A `deformable body`_ is a single body (either surface or volume deformable) that can be simulated by PhysX. Unlike rigid bodies, deformable bodies support relative motion of the nodes in the mesh. Consequently, they can be used to simulate deformations under applied forces. PhysX deformable body simulation employs Finite Element Analysis (FEA) to simulate the deformations of the mesh. It uses two meshes to represent the deformable body: 1. **Simulation mesh**: This mesh is used for the simulation and is the one that is deformed by the solver. 2. **Collision mesh**: This mesh only needs to match the surface of the simulation mesh and is used for collision detection. For most applications, we assume that the above two meshes are computed from the "render mesh" of the deformable body. The render mesh is the mesh that is visible in the scene and is used for rendering purposes. It is composed of triangles, while the simulation mesh is composed of tetrahedrons for volume deformables, and triangles for surface deformables. .. caution:: The deformable body schema is still under development by the Omniverse team. The current implementation works with the PhysX schemas shipped with Isaac Sim 6.0.0 onwards. It may change in future releases. .. 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. .. _deformable body: https://nvidia-omniverse.github.io/PhysX/physx/5.6.1/docs/DeformableVolume.html .. _PhysxDeformableBodyAPI: https://docs.omniverse.nvidia.com/kit/docs/omni_usd_schema_physics/latest/physxschema/annotated.html Args: prim_path: The prim path to the deformable body. cfg: The configuration for the deformable body. stage: The stage where to find the prim. Defaults to None, in which case the current stage is used. Returns: True if the properties were successfully set, False otherwise. """ # get stage handle if stage is None: stage = get_current_stage() # get deformable-body USD prim deformable_body_prim = stage.GetPrimAtPath(prim_path) # check if the prim is valid if not deformable_body_prim.IsValid(): return False # check if deformable body API is applied if "OmniPhysicsDeformableBodyAPI" not in deformable_body_prim.GetAppliedSchemas(): return False # apply customization to deformable API if "PhysxBaseDeformableBodyAPI" not in deformable_body_prim.GetAppliedSchemas(): deformable_body_prim.AddAppliedSchema("PhysxBaseDeformableBodyAPI") # ensure PhysX collision API is applied on the collision mesh if "PhysxCollisionAPI" not in deformable_body_prim.GetAppliedSchemas(): deformable_body_prim.AddAppliedSchema("PhysxCollisionAPI") # convert to dict cfg = cfg.to_dict() # set into PhysX API if cfg["kinematic_enabled"]: logger.warning( "Kinematic deformable bodies are not fully supported in the current version of Omni Physics. " "Setting kinematic_enabled to True may lead to unexpected behavior." ) # prefixes for each attribute (collision attributes: physxCollision:*, and physxDeformable:* for rest) property_prefixes = cfg["_property_prefix"] for prefix, attr_list in property_prefixes.items(): for attr_name in attr_list: safe_set_attribute_on_usd_prim( deformable_body_prim, f"{prefix}:{to_camel_case(attr_name, 'cC')}", cfg[attr_name], camel_case=False ) # success return True