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_typebecomesphysxScene:solverType("TGS"or"PGS").bounce_threshold_velocitybecomesphysxScene:bounceThreshold.The timestep becomes
physxScene:timeStepsPerSecond.GPU simulation enables GPU dynamics and the GPU broadphase. CPU simulation uses the MBP broadphase.
enable_ccdtakes effect only on CPU. CCD is disabled with a warning when GPU dynamics is enabled.The backend-agnostic
deterministicrequest enablesenable_enhanced_determinism.Scene query support follows
SimulationCfg.enable_scene_query_supportand 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
PhysxBackendCfgwith the simulation context. The resultingPhysxBackendowns theomni.physics.tensorssimulation view, created with the Warp frontend for the current stage. Finally, the manager dispatchesPHYSICS_READY, and assets and sensors create their typed views from the simulation view.- Step
Advances PhysX through the
omni.physxsimulation interface withsimulate(dt)followed byfetch_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(), andstop()driveomni.timelineand 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:
|
|
Dispatched |
|---|---|---|
|
|
After the warm-start update |
|
|
After the tensor view exists |
|
|
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.