Change pose of triangle mesh collider during GPU physX simulation

Isaac Sim Version

5.0.0

Operating System

Ubuntu 22.04

GPU Information

  • Model: RTX 3090

Topic Description

Detailed Description

I’m using Isaac Sim to do reinforment learning. Normally we will create parallel env(room) to let multiple robot to play in. And when a robot finishes a game, the room is reset, for example, obstacles be randomized and robot reset to initial random pose.

One thing I found now working is that, I cannot create such object that fulfills all the following request:

  1. The physX works in GPU mode, not CPU mode. The simulation speed is crucial for RL
  2. The object is represented by a triangle mesh, not convex shapes. It serves as a static collider, such as static obstacles.
  3. The object can be transformed to another location using python code. Calling some omni/isaac/physx API to modify the position and orientation of this object.

I tried different method:

If I use rigid body with kinematic turned on, then we know the rigid body do not accept arbitrary triangle mesh as collider, falling back to convex hull, which is not good for me

If I use non-rigid-body static collider, which supports triangle mesh, then once the GPU physX is initialized (the triangle mesh is baked as AABB tree during this init I think), and cannot be transformed to new places during simulation. There is no such entry in the pytorch tensor physX API.

I wonder is there an option to let the GPU physX pipeline rebuild all static mesh ? Reading vertices and faces from the USD scene tree and build again the AABB tree ?

I have a piece of code here to represent what I want:

import os
import isaacsim

use_full_exp_file = True
simulation_app = isaacsim.SimulationApp(
    launch_config={"headless": False},
    experience=os.path.join(os.path.dirname(isaacsim.__file__), "apps/isaacsim.exp.full.kit") if use_full_exp_file else None,
)

import torch
import omni
from pxr import Usd, UsdGeom, Gf, UsdPhysics, Sdf, UsdLux, PhysxSchema
from isaacsim.core.simulation_manager import SimulationManager
from isaacsim.core.api import SimulationContext
from isaacsim.core.api.objects.ground_plane import GroundPlane
from isaacsim.core.utils.viewports import set_camera_view


FRAME_RATE = 60
RENDER_DECIMATION = 1

def create_cube(prim_path: str, rigid_body: bool, kinematic: bool, center: list[float], size: list[float]):
    stage = omni.usd.get_context().get_stage()

    distantLight = UsdLux.DistantLight.Define(stage, Sdf.Path("/Light"))
    distantLight.CreateIntensityAttr(3000)

    xform = UsdGeom.Cube.Define(stage, prim_path)
    xform.CreateSizeAttr().Set(1.0)

    xform.AddTranslateOp(UsdGeom.XformOp.PrecisionDouble).Set(Gf.Vec3d(center[0], center[1], center[2]))
    xform.AddOrientOp(UsdGeom.XformOp.PrecisionDouble).Set(Gf.Quatd(1.0, 0.0, 0.0, 0.0))
    xform.AddScaleOp(UsdGeom.XformOp.PrecisionDouble).Set(Gf.Vec3d(size[0], size[1], size[2]))

    collision_api = UsdPhysics.CollisionAPI.Apply(xform.GetPrim())
    if rigid_body:
        rigid_body_api = UsdPhysics.RigidBodyAPI.Apply(xform.GetPrim())
        if kinematic:
            rigid_body_api.CreateKinematicEnabledAttr().Set(True)

def init_physics():
    SimulationManager.initialize_physics()
    physics_sim_view = SimulationManager.get_physics_sim_view()
    physx_view = physics_sim_view.create_rigid_body_view(["/World/Box2"])
    
    return physx_view

def main():
    sim = SimulationContext(
        physics_dt=1 / FRAME_RATE, 
        rendering_dt=1 / FRAME_RATE, 
        backend='torch', 
        device='cuda:0',
    )
    
    # Get USD stage for direct manipulation
    stage = omni.usd.get_context().get_stage()
    
    GroundPlane(prim_path="/World/GroundPlane", z_position=0, size=10.0)
    create_cube(
        prim_path="/World/Box1", 
        rigid_body=False,
        kinematic=False, 
        center=[0, 1, 2], 
        size=[1, 1, 1],
    )
    create_cube(
        prim_path="/World/Box2", 
        rigid_body=True,
        kinematic=False, 
        center=[0, 1, 5], 
        size=[1, 1, 1],
    )
    physx_view = init_physics()
    physics_sim_view = SimulationManager.get_physics_sim_view()
    
    set_camera_view(
        eye=[12.0, 0.0, 3], 
        target=[0.0, 0.0, 2.0], 
        camera_prim_path="/OmniverseKit_Persp"
    ) 

    sim.reset()

    # Define simulation stepping
    frame = 0
    # Simulate physics
    while simulation_app.is_running():
        # perform step
        sim.step()

        frame += 1
        if frame % 100 == 0:
            print(f"Stepped {frame} frames")

        if frame % 300 == 0:
            # Move Box1 (static collider) via USD API
            box1_prim = stage.GetPrimAtPath("/World/Box1")
            xformable = UsdGeom.Xformable(box1_prim)
            translate_op = xformable.GetOrderedXformOps()[0]
            translate_op.Set(Gf.Vec3d(0.0, 1.0, 2.0))
            
            # Move Box2 (dynamic rigid body) via PhysX view
            tf = physx_view.get_transforms()
            print(f"Transforms at frame {frame}: {tf}")
            tf[0, 0] = 0.0
            tf[0, 1] = 1.0
            tf[0, 2] = 5.0
            physx_view.set_transforms(tf, indices=torch.arange(len(tf), device='cuda:0'))

            
            assert physics_sim_view.check()

        if frame % 300 == 150:
            # Move Box1 (static collider) via USD API
            box1_prim = stage.GetPrimAtPath("/World/Box1")
            xformable = UsdGeom.Xformable(box1_prim)
            translate_op = xformable.GetOrderedXformOps()[0]
            translate_op.Set(Gf.Vec3d(0.0, -1.0, 2.0))
            
            # Move Box2 (dynamic rigid body) via PhysX view
            tf = physx_view.get_transforms()
            print(f"Transforms at frame {frame}: {tf}")
            tf[0, 0] = 0.0
            tf[0, 1] = -1.0
            tf[0, 2] = 5.0
            physx_view.set_transforms(tf, indices=torch.arange(len(tf), device='cuda:0'))


if __name__ == "__main__":
    main()
    simulation_app.close()

Screenshots or Videos

The video of the above code. I want to update the pose of the static collider, of course currently the GPU physX pipeline will not update the static triangle mesh collider at each frame. But if there is at least an option to trigger the rebuild manually ?

Hi, Can you try in Isaac Sim 5.1.0? I think we have some fixes regarding set_transforms not working in 5.0.0, please give it a try.

I think I misunderstood your question in previous comment.

If your ask is:

I want to update the pose of the static collider, of course currently the GPU physX pipeline will not update the static triangle mesh collider at each frame.

I think you cannot use the GPU PhysX pipeline, because the static collider is not a rigid body and will not participate the physics simulation.

Actually static collider DID participate the physics simulation, serving as walls or other static obstacles for rigid bodies to collide on. But the problem is that PhysX python Tensor API do not have a function to force resetting static colliders.

In that sense I agree with you. But since the static colliders are static and their positions are not supposed to be changed by the PhysX pipeline during simulation, I think it still makes sense there’s no resetting Tensor API for it in PhysX.