isaaclab_physx.sim.views#

PhysX simulation views.

Classes#

The following classes are part of the public isaaclab_physx.sim.views API.

FabricFrameView

FrameView with Fabric GPU acceleration for the PhysX backend.

class isaaclab_physx.sim.views.FabricFrameView[source]#

Bases: BaseFrameView

FrameView with Fabric GPU acceleration for the PhysX backend.

Uses composition: holds a UsdFrameView internally for USD fallback and non-accelerated operations (visibility, and all pose/scale operations when Fabric is disabled).

When Fabric is enabled, world-pose, local-pose, and scale operations run on the GPU via Warp kernels that read and write omni:fabric:worldMatrix and omni:fabric:localMatrix directly. All other operations delegate to the internal USD view.

All writes go through the writer-scope API (xform_world_space_writer() / xform_local_space_writer(), recommended) or the convenience set_world_poses() / set_local_poses() / etc. helpers inherited from BaseFrameView.

Behavior (Fabric path):

  • Leaf-prim assumption. This view manages a flat set of sibling prims (e.g. all cameras under /World/Env_*/Camera). It does NOT propagate transforms to child prims. If a managed prim has children whose world matrices depend on the parent, those children must be updated via a separate view, a physics step, or IFabricHierarchy.update_world_xforms.

  • No write-back to USD. Fabric writes update only omni:fabric:worldMatrix / omni:fabric:localMatrix; the prim’s USD xformOp:* attributes are unchanged. Downstream consumers that read the prim’s USD attributes after a Fabric write will see stale values until the next USD-side sync.

  • Eager dual-write inside a writer scope (no dirty tracking). When a writer scope is open, all writes go to the primary attribute (worldMatrix for the world writer, localMatrix for the local writer). On scope exit, a single Warp kernel derives the opposite attribute and a single wp.synchronize() runs. After the scope exits, both Fabric matrices are self-consistent. Getters launch their own decompose kernel and wp.synchronize() before returning, so a returned ProxyArray is always immediately readable from either GPU or host code (no caller-side sync required).

    The opposite-space derive runs even when the scope unwinds via exception (including KeyboardInterrupt in interactive notebooks), as a best-effort to keep worldMatrix and localMatrix mutually consistent on whatever partial-write state Fabric holds. The partial write itself is not rolled back – if you need transactional all-or-nothing semantics, snapshot the matrices yourself before entering the scope.

  • Fabric Hierarchy listeners are paused while a writer scope is active when the hierarchy bindings are available. On enter, the writer calls IFabricHierarchy.track_local_xform_changes(False)() / track_world_xform_changes(False)() (saving the prior state). Fabric itself is just a flat attribute store; the plugin that keeps omni:fabric:worldMatrix and omni:fabric:localMatrix mutually consistent across the prim hierarchy is usdrt.hierarchy.IFabricHierarchy (a.k.a. Fabric Hierarchy). Its change tracking is pull-based: a per-attribute listener records writes into a private changelog, and the plugin drains and processes that changelog on the next call to IFabricHierarchy::update_world_xforms() (typically from the render path). “Tracking off” just stops the listener from recording new entries – writes still land in Fabric storage; they are simply invisible to the next update_world_xforms() call.

    That is exactly what we want. Inside the scope we write one space (world or local) and, at scope exit, derive the other in a single batched kernel so both matrices are mutually consistent. If tracking were left on, our writes would be queued in the changelog and the next update_world_xforms() tick would process them – choosing a canonical direction (e.g. “user authored local, recompute world from it”) and potentially overwriting one half of our just-consistent pair. With tracking paused for the duration of the scope, the changelog stays empty for these prims and the next tick is a no-op for them.

    __exit__ restores the prior tracking state (so we do not re-enable listeners the caller had previously paused). The Fabric Scene Delegate (FSD) reads omni:fabric:worldMatrix directly from Fabric storage on the render path; it observes our final writes unchanged.

    Headless experiences without FSD do not expose the hierarchy Python bindings and do not run hierarchy update ticks. In that case the writer skips listener pause/restore while retaining the same direct Fabric matrix writes.

    Note: the scope is synchronous Python code, so no simulation step and no render tick can run while it is open – callers must not advance the simulation from inside the scope (see isaaclab.sim.views.xform_space_writer for the full contract). The “torn data” concern is what motivates that no-step rule; it is separate from why the tracking pause exists.

  • Selections are scoped to the view, not the stage. The view tags its own prims (and their parents) with private per-view index attributes and requires those attributes in every prim selection, so a selection resolves to exactly the prims the view manages however large the stage grows. Tag names are unique per view instance, so views never interfere with one another. The tags are authored on first use and removed again by close() – or, best-effort and with a warning, when the view is garbage collected. Call close() when done with a view; collection timing is up to the interpreter, so relying on it can remove the tags at an arbitrary point in the frame (or, on a leaked reference, not at all).

  • Topology changes are absorbed, with no cache to invalidate. The view-to-Fabric mapping is re-derived from live Fabric data on every access, so prims moving between Fabric buckets can never leave a stale mapping behind. If a managed prim disappears (prim or attribute removed) the next access raises RuntimeError and the view must be recreated. See _refresh_child_selection for how this is done.

Pose getters return ProxyArray; the convenience set_world_poses() / set_local_poses() helpers accept wp.array. Inside a writer scope, the writer’s set_poses() / set_scales() accept wp.array.

Methods:

__init__(prim_path[, device, ...])

Initialize the view.

__new__(*args, **kwargs)

__init__(prim_path: str, device: str = 'cpu', validate_xform_ops: bool = True, stage: Stage | None = None, **kwargs)[source]#

Initialize the view.

Parameters:
  • prim_path – USD prim-path pattern to match.

  • device – Device for Warp arrays. Either "cpu" or any CUDA device string ("cuda:0", "cuda:1", …); Fabric acceleration is supported on every CUDA index.

  • validate_xform_ops – Whether to validate prim xform-ops.

  • stage – USD stage; defaults to the current sim context’s stage.

  • **kwargs – Additional keyword arguments (ignored). Matches the signature of UsdFrameView so that the top-level FrameView factory can forward backend-agnostic kwargs without each backend having to know about every option.

classmethod __new__(*args, **kwargs)#