Skip to navigation

PhysX Backend (Isaac Sim)

View as Markdown

The PhysX backend runs NVIDIA PhysX inside Isaac Sim, on the Omniverse Kit runtime. Its integration lives in the isaaclab_physx package. This page explains how that package starts Kit, owns the simulation lifecycle, configures the PhysX scene, and exposes native PhysX data to Isaac Lab assets and sensors. For solver selection and tuning, see PhysX and Tune the PhysX Solver. For the kit-less PhysX path, see OvPhysX Backend.

Selecting the backend

Configure the backend with ~isaaclab_physx.physics.PhysxCfg on isaaclab.sim.SimulationCfg.physics, or select it from the command line with physics=isaacsim_physx when the task exposes that preset:

from isaaclab.sim import SimulationCfg
from isaaclab_physx.physics import PhysxCfg
sim_cfg = SimulationCfg(physics=PhysxCfg())

The physx selector is automatic. It selects a ~isaaclab.physics.PhysxAutoCfg that holds a PhysxCfg and, when the task supports it, an ~isaaclab_ov.physics.OvPhysxCfg. When the simulation is launched, the auto configuration resolves to Isaac Sim PhysX if the run needs Kit, and otherwise to OvPhysX when one is configured. Use isaacsim_physx to require the Isaac Sim path.

Runtime: Isaac Sim and Kit

Launch

PhysxCfg names its launcher through the launcher_type class attribute, which is isaaclab_physx.app:KitLauncher. ~isaaclab.app.launch_simulation scans the resolved configuration, collects the launchers that the physics and renderer configurations name, and starts them. Kit starts first. Scripts do not construct the launcher themselves.

~isaaclab_physx.app.KitLauncher creates the Isaac Sim SimulationApp. Unless --experience is passed, it selects an Isaac Lab experience file from the repository apps/ directory based on the headless, camera-rendering, livestream, and XR settings, for example isaaclab.python.headless.kit or isaaclab.python.rendering.kit. After startup it publishes Isaac Lab settings such as /isaaclab/has_gui that the simulation context and renderers read. The launcher’s environment variables and arguments are documented in isaaclab_physx.app.

Stage

Isaac Lab owns the USD stage. Kit extensions, including PhysX, its tensor views, and the viewport, read the stage from Kit’s USD context instead. When Kit is running, ~isaaclab.sim.SimulationContext registers a ~isaaclab_physx.app.KitStageBackendCfg, and ~isaaclab_physx.app.KitStageBackend attaches the simulation stage to omni.usd’s context. Closing that backend closes the Kit stage before the simulation clears its stage cache.

Interaction with Isaac Sim’s simulation manager

~isaaclab_physx.physics.PhysxManager is the single owner of the simulation lifecycle. Isaac Sim’s own isaacsim.core.simulation_manager.SimulationManager registers default timeline and stage callbacks. Its stop callback invalidates the shared omni.physics.tensors simulation view, which would also invalidate the views that Isaac Lab assets hold. KitLauncher asks Isaac Sim to skip these callbacks at startup through the /exts/isaacsim.core.simulation_manager/enable_default_callbacks setting. Newer Isaac Sim versions honor it, and Isaac Lab then leaves the manager untouched. On older versions, PhysxManager.initialize() disables those callbacks and redirects the module’s SimulationManager to PhysxManager. PhysxManager re-applies this patch if the Isaac Sim extension is enabled later.

Simulation lifecycle

PhysxManager implements the shared ~isaaclab.physics.PhysicsManager contract on top of the omni.physx, omni.physics.tensors, and omni.timeline interfaces:

initialize() Kit physics settings, PhysxSceneAPI attributes, Fabric
│
reset() first call: attach stage, warm start, create the tensor view,
│ dispatch PHYSICS_READY (assets and sensors create their views)
│
step() omni.physx simulate(dt) + fetch_results()
│
close() detach stage, invalidate views, release the tensor view

Initialization Applies Kit physics settings such as the CUDA device and GPU readback suppression, authors the PhysX scene attributes described in Scene configuration_, binds a default physics material, and loads or unloads the PhysX Fabric extension.

First reset Attaches the stage to PhysX (on CPU, PhysX instead loads the scene directly from USD), runs one warm-start update, and dispatches the warm-up event. It then registers a ~isaaclab_physx.physics.PhysxBackendCfg with the simulation context. The resulting PhysxBackend owns the omni.physics.tensors simulation view, created with the Warp frontend for the current stage. Finally, the manager dispatches PHYSICS_READY, and assets and sensors create their typed views from the simulation view.

Step Advances PhysX through the omni.physx simulation interface with simulate(dt) followed by fetch_results(). Physics stepping does not pump the Kit application. Rendering is driven separately by the simulation context. forward() refreshes articulation kinematics through the tensor view only when pose writes have marked them dirty.

Timeline and teardown play(), pause(), and stop() drive omni.timeline and pump one Kit update so timeline callbacks run synchronously. Stopping the timeline invalidates every tensor view. The next play or reset warms up PhysX and creates the views again. close() detaches PhysX from the stage before views are invalidated and prims are deleted.

Lifecycle events

Backend-agnostic code registers callbacks with ~isaaclab.physics.PhysicsEvent. PhysxManager maps those events to its PhysX-specific ~isaaclab_physx.physics.IsaacEvents, which remain available for backward compatibility:

PhysicsEventIsaacEventsDispatched
MODEL_INITPHYSICS_WARMUPAfter the warm-start update
PHYSICS_READYPHYSICS_READYAfter the tensor view exists
STOPTIMELINE_STOPWhen the timeline stops

IsaacEvents also exposes PRE_PHYSICS_STEP and POST_PHYSICS_STEP through the omni.physx step subscription, and PRIM_DELETION during teardown. New code should prefer PhysicsEvent.

Scene configuration

PhysxCfg fields are written to the physics scene prim at isaaclab.sim.SimulationCfg.physics_prim_path. The manager applies PhysxSceneAPI and sets each remaining field as a physxScene: attribute in camel case, for example gpu_max_rigid_contact_count becomes physxScene:gpuMaxRigidContactCount. Some fields are translated instead of copied:

  • solver_type becomes physxScene:solverType ("TGS" or "PGS").
  • bounce_threshold_velocity becomes physxScene:bounceThreshold.
  • The timestep becomes physxScene:timeStepsPerSecond.
  • GPU simulation enables GPU dynamics and the GPU broadphase. CPU simulation uses the MBP broadphase.
  • enable_ccd takes effect only on CPU. CCD is disabled with a warning when GPU dynamics is enabled.
  • The backend-agnostic deterministic request enables enable_enhanced_determinism.
  • Scene query support follows SimulationCfg.enable_scene_query_support and is forced on when Kit runs with a GUI.

Per-prim physics properties are not part of PhysxCfg. They are authored through the USD schema configurations described in /source/concepts/schema_cfgs. PhysX-only schema configurations, such as ~isaaclab_physx.sim.schemas.PhysxRigidBodyPropertiesCfg, live in isaaclab_physx.sim.schemas.

Fabric

When isaaclab.sim.SimulationCfg.use_fabric is True, the default, the manager enables the omni.physx.fabric extension. It also turns off PhysX write-back to USD (/physics/updateToUsd and related settings), so simulated transforms reach the renderer through Fabric instead of USD. With use_fabric=False, PhysX writes simulation results back to USD, which is slower for large scenes.

Tensor views and native access

The PhysX Tensor API provides typed views for data paths and capabilities that require engine-native access.

Every PhysX asset and sensor in isaaclab_physx, except SurfaceGripper, is built on typed views created from the shared omni.physics.tensors simulation view:

Isaac Lab classNative view
Articulation, joint wrench sensorArticulation view
Rigid object, rigid object collectionRigid-body view
Deformable objectSurface or volume deformable-body view and deformable-material view
Contact sensorRigid-body view and rigid-contact view
IMU, frame transformer, ray caster, and similar sensorsRigid-body view of the tracked bodies

Assets expose their view through root_view. The contact sensor exposes its rigid-contact view through contact_view. Use ~isaaclab_physx.physics.PhysxManager.get_physics_sim_view to reach the simulation view itself after the first reset.

Environment cloning uses ~isaaclab_physx.cloner.PhysxReplicateContext, which applies the clone plan through the omni.physx replicator interface.

Mental model

The API starts from a SimulationView and creates typed views over selected physics objects. Access is entirely method-based: a getter pulls data from the view, and an independent setter publishes data back. Returned buffers are not live pointers, so editing a getter result does not update the simulation. Raw views select objects with PhysX Tensor API wildcard patterns.

Lifecycle prerequisite

~isaaclab_physx.physics.PhysxManager creates its SimulationView with the Warp frontend. Low-level code must run only after physics initialization and simulation reset, when the PhysX Tensor API view has been created:

from isaaclab_physx.physics import PhysxManager
simulation_view = PhysxManager.get_physics_sim_view()
if simulation_view is None:
raise RuntimeError("PhysX Tensor API is not ready; initialize and reset the simulation first.")

Reuse Isaac Lab-owned access

When an Isaac Lab asset already has the desired selection, reuse its isaaclab_physx.assets.Articulation.root_view rather than creating a second view:

robot = scene["robot"]
articulation_view = robot.root_view
joint_positions = articulation_view.get_dof_positions()

isaaclab_physx.assets.Articulation.root_view is backend-specific and typed. An articulation, rigid object, rigid-object collection, or deformable can expose a different native PhysX view type, so choose methods that match the returned view rather than assuming one common interface.

Create raw access

Create a view directly only when no Isaac Lab-owned selection matches the needed objects or capability. In this Tensor API pattern, * selects the matching object below every cloned environment:

rigid_body_view = simulation_view.create_rigid_body_view(
"/World/envs/env_*/Object"
)

Read/write semantics

Each getter and setter is a separate operation. Clone a returned Warp buffer before editing it locally, then call the matching setter to publish the result:

import warp as wp
poses = wp.clone(rigid_body_view.get_transforms())
indices = wp.array(
range(poses.shape[0]),
dtype=wp.int32,
device=poses.device,
)
rigid_body_view.set_transforms(poses, indices)

Cloning makes ownership explicit. Callers can modify the clone with Warp before the setter, but edits to a local buffer do not publish themselves. The indices array selects the complete view and matches the setter’s required int32 dtype and device; the setter performs the write. For active Tensor API contracts that require link transforms to be refreshed after joint-state writes, call update_articulations_kinematic(). Not every setter requires that refresh; follow the method-level behavior in the upstream reference.

Access the contact view

The PhysX contact sensor exposes its native RigidContactView through isaaclab_physx.sensors.ContactSensor.contact_view. Use it when the public sensor data does not expose the required contact details:

contact_sensor = scene["contact_sensor"]
friction_forces, _, buffer_counts, buffer_start_indices = (
contact_sensor.contact_view.get_friction_data(dt=sim.cfg.dt)
)

Other Isaac Lab sensors may use ordinary rigid-body or articulation views internally, but those views are not sensor-specific low-level interfaces.

Ownership, synchronization, and invalidation

Preserve a view’s expected selection ordering, device, dtype, and tensor shape when supplying values to a setter. Check and reacquire views after a hard reset, object removal, stage reload, or manager teardown. Prefer public Isaac Lab sensor data when direct native contact or motion data is not required.

Authoritative references

PhysX-specific and shared components

AreaShared (isaaclab)PhysX-specific (isaaclab_physx)
Configuration~isaaclab.sim.SimulationCfg, PhysicsCfg, and ~isaaclab.physics.PhysxAutoCfgPhysxCfg and PhysxBackendCfg
Runtime~isaaclab.app.launch_simulation and SimulationLauncherKitLauncher and KitStageBackend
LifecyclePhysicsManager and PhysicsEventPhysxManager and IsaacEvents
Assets and sensorsBase classes, factories, and public data contractsImplementations built on omni.physics.tensors views, plus SurfaceGripper, which uses Isaac Sim’s surface-gripper extension
CloningClone planPhysxReplicateContext
USD schemasShared schema configurationsPhysx* schema configurations in isaaclab_physx.sim.schemas
Scene data~isaaclab.scene_data.SceneDataProviderA scene-data backend that reads poses from the tensor view or Fabric

Kit-hosted rendering, such as the ~isaaclab_physx.renderers.IsaacRtxRendererCfg renderer, also ships in isaaclab_physx because it requires Kit. Renderer selection is configured separately from the physics backend, but the kit-less OVRTX renderer cannot share a process with Isaac Sim PhysX. See Backend architecture for the factory and registry design that all backends share.