IsaacSim PhysX#

The PhysX backend runs inside Isaac Sim through the isaaclab_physx package. See Tune the PhysX Solver for solver settings and tuning, or OvPhysX for PhysX without Kit.

Selecting the backend#

Configure the backend with 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 PhysxAutoCfg that holds a PhysxCfg and, when the task supports it, an 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.

Scene configuration#

PhysxCfg fields are written to the physics scene prim at 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 Physics Schemas. PhysX-only schema configurations, such as PhysxRigidBodyPropertiesCfg, live in isaaclab_physx.sim.schemas.

Fabric#

When 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.

Runtime: Isaac Sim and Kit#

Launch#

PhysxCfg names its launcher through the launcher_type class attribute, which is isaaclab_physx.app:KitLauncher. 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.

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, SimulationContext registers a KitStageBackendCfg, and 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#

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 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 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 PhysicsEvent. PhysxManager maps those events to its PhysX-specific IsaacEvents, which remain available for backward compatibility:

PhysicsEvent

IsaacEvents

Dispatched

MODEL_INIT

PHYSICS_WARMUP

After the warm-start update

PHYSICS_READY

PHYSICS_READY

After the tensor view exists

STOP

TIMELINE_STOP

When 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.

Tensor views and native access#

Use native access when the shared asset and sensor APIs do not expose the data or operation you need. Reuse an Isaac Lab-owned handle when its selection matches; create raw access only for additional capabilities. Native writes can bypass Isaac Lab’s caches and validation, so follow the ownership and synchronization rules below.

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 class

Native view

Articulation, joint wrench sensor

Articulation view

Rigid object, rigid object collection

Rigid-body view

Deformable object

Surface or volume deformable-body view and deformable-material view

Contact sensor

Rigid-body view and rigid-contact view

IMU, frame transformer, ray caster, and similar sensors

Rigid-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 get_physics_sim_view() to reach the simulation view itself after the first reset.

Environment cloning uses 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#

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 root_view rather than creating a second view:

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

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 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#

Area

Shared (isaaclab)

PhysX-specific (isaaclab_physx)

Configuration

SimulationCfg, PhysicsCfg, and PhysxAutoCfg

PhysxCfg and PhysxBackendCfg

Runtime

launch_simulation() and SimulationLauncher

KitLauncher and KitStageBackend

Lifecycle

PhysicsManager and PhysicsEvent

PhysxManager and IsaacEvents

Assets and sensors

Base classes, factories, and public data contracts

Implementations built on omni.physics.tensors views, plus SurfaceGripper, which uses Isaac Sim’s surface-gripper extension

Cloning

Clone plan

PhysxReplicateContext

USD schemas

Shared schema configurations

Physx* schema configurations in isaaclab_physx.sim.schemas

Scene data

SceneDataProvider

A scene-data backend that reads poses from the tensor view or Fabric

Kit-hosted rendering, such as the 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.