Python API Reference#

High-level Python API for the ovphysx library.

Stream-Ordered Execution Model#

Operations on each instance execute in submission order. Submission may execute inline; the task contract still separates admission from completion:

  • Operations appear to complete in submission order

  • Writes from operation N are visible to operation N+1

  • Wait for a creator before passing its output handle to another operation

  • Independent operations may execute concurrently internally for performance

Example using the explicit synchronous read convenience:

Listing 1 Stream-ordered operation sequence#
 from ovphysx.types import ObjectScope, SimObjectType

 def step_and_read(physx, stage, initial_ordinal, from_ordinal, to_ordinal, dt):
     physx.wait_task(physx.attach_ovstage(stage, read_ordinal=initial_ordinal))
     # After the application authors later ovstage edits:
     physx.wait_task(physx.update_from_ovstage(from_ordinal, to_ordinal))
     physx.step(dt)  # Sees the drained stage edits
     with physx.read_sync(
         SimObjectType.RIGID_BODY, ["position"], scope=ObjectScope.ALL
     ) as result:  # Reads current state
         for group in result.groups:
             for tensor in group.tensors:
                 print(tensor.numpy())

Use Operation.wait(), wait_task(), or wait_all() when:

  • Before materializing an operation’s typed result

  • To ensure operations complete before program exit

  • For explicit synchronization points in your application

Host task collection and CUDA stream dependencies are separate. Materializing a read group orders its producer event onto the current Warp stream. A write commit’s stream and event describe the caller’s producer completion; they do not select the stream PhysX uses for its own work.

Thread Safety#

  • Each instance holds at most one live ovstage attach. Several instances may be attached at once, and attaching one does not detach another. The same ovstage instance cannot be attached to two PhysX instances.

  • Different instances may step their own attachments at the same time. A single instance is NOT thread-safe. Use external synchronization if calling from multiple threads on the same instance.

  • Process-wide limits still apply: one hard CPU-only mode, one SDK tolerance scale, and a recording start/stop that needs every attached instance idle.

  • ctypes releases the GIL during native calls, so concurrent step() and PhysX.read() / PhysX.write() from different threads on the same instance is a data race. See the developer guide threading section for the recommended pattern.

Core Classes#

class ovphysx.api.PhysX(
*,
config: PhysXConfig | None = None,
ignore_version_mismatch: bool = False,
active_cuda_gpus: str | None = None,
)#

Bases: object

High-level wrapper around the C API using ctypes.

attach_ovstage(
stage,
*,
read_ordinal: int = 1,
) → Task#

Attach an ovstage Stage and return its Task receipt.

Attach performs the initial scene parse at read_ordinal. After the producer authors later ovstage edits, call update_from_ovstage() with only those subsequent ordinals. Tensor bindings remain available as a perf escape hatch.

Execution currently runs inline. Collect the returned Task with wait_task() or wait_all() before using the attachment; accepted execution failures are reported by that wait.

Parameters:
  • stage – An owner-aware ovstage.Stage; raw pointers are a low-level C integration.

  • read_ordinal – Caller-owned ovstage ordinal at which selected physics data is sealed. Must be non-zero. 0 is reserved as the runtime skip-cursor sentinel. The application owns ordinal advancement. Defaults to 1. open_usd() / population does not seal data, so call advance_write_floor() first. Attachment fails if the initial articulation/joint schema scan cannot read that ordinal.

Preconditions:
  • Instance must be valid.

  • Not already attached to a Stage.

  • No other instance is required to detach first. Several instances may be attached at once. This call does not detach them.

  • Selected physics data must be sealed at read_ordinal.

  • read_ordinal must be non-zero.

  • The application registered the codeless PhysX schemas with ovstage before the first USD schema read, including population or export, in each process and worker, using both resource directories from the separately installed physx-usd-schemas provider (see the samples). Population drops attributes of schemas it cannot resolve. If ovstage reports that either physxSchema or omniUsdPhysicsDeformableSchema was missing when its USD schema registry was built, the native guard rejects admission and this method raises RuntimeError before returning a Task or taking Stage ownership. The refusal persists for the process: restart and register before populating or exporting. A procedural Stage attached while USD schema definitions remain unbuilt skips the family check, leaving it active for later attaches. Once population or export builds the definitions, even procedural Stages are checked. Registration another USD consumer made unobservable to ovstage cannot be detected. Nor can the guard identify schema families registered late before its first check: catching a late registration’s OvstageError can let a later attach succeed with missing data. Always restart after a registration-ordering error; successful attach does not prove schema availability during population. The legacy setting /ovphysx/schemas/requireRegistration defaults to true; setting it to false with PhysXConfig(carbonite_overrides=...) permits attach with a warning but does not repair lost data.

  • Scenes that author Newton newton:* attributes need the Newton USD schema (pip install newton-usd-schemas) registered in the same call (ovphysx.newton_schema_root()); population drops those attributes otherwise. Before the native attach this call checks the installed package’s registration once per process and emits a RuntimeWarning if ovstage reports late registration; a warning promoted to an error therefore leaves the instance detached. When the package is not installed it logs a warning on the ovphysx logger instead (nothing is wrong for scenes without newton:* attributes, and suites that promote warnings to errors stay unaffected). The check probes only once USD has built its schema definitions, including through export. A procedurally authored stage attached while those definitions remain unbuilt is left alone, so the check never registers a schema on the application’s behalf. It recognizes the Newton schema family registered from any complete copy. The setting /ovphysx/schemas/warnMissingNewtonSchema = false (PhysXConfig(carbonite_overrides=...), "false" accepted) silences the check, for a registration ovstage cannot observe. This Newton check does not check either PhysX schema family; silencing it does not bypass the native PhysX registration guard.

Lifetime:
  • stage must outlive the attachment because ovphysx captures and dereferences its native pointer until detach. This wrapper holds a reference to stage for the duration of the attachment, so a Stage created inline (attach_ovstage(ovstage.Stage(...))) stays alive. The reference is held from module scope, so garbage collection of an unreachable cycle containing this instance cannot finalize the Stage before the instance’s teardown detaches it. The reference survives pending or failed teardown, and is dropped when a lifecycle task is collected and native ownership has ended, or by destroy().

Returns:

Immutable Task receipt. Its SUCCESS status means admission only.

Errors:
  • Raises TypeError if stage is not an owner-aware ovstage.Stage, including None or a raw native handle.

  • Propagates ovstage.OvstageError if stage was destroyed.

  • Raises ValueError if read_ordinal is 0.

  • Raises RuntimeError if this instance is already attached, the Stage’s native handle is null, the native PhysX schema guard refuses the process, or submission is otherwise rejected. A schema refusal creates no Task and changes no attachment.

  • Accepted execution failures raise TaskError when collected. Failed rollback can leave an attachment; use is_stage_attached() after collection to check ownership. A peer instance’s attachment is left in place.

clone(
source_path: str,
target_paths: list[str],
anchor_transforms: list[tuple[float, float, float, float, float, float, float]] | None = None,
env_ids: list[int] | None = None,
) → Task#

Clone a prim hierarchy to create multiple runtime physics copies.

Creates physics-optimized clones in the runtime representation for high-performance simulation, backed by the PhysX SDK replicator so cloned articulations are real articulations. The source prim must exist in the loaded stage and have physics properties. Replication executes inline. The returned Task is already complete. On success subsequent operations see the clone immediately. Accepted execution failures are reported by wait_task() or wait_all(); the receipt’s SUCCESS status describes admission, not execution.

This is the clone entrypoint for both standalone callers and callers that populate the scene through an ovstage Stage attached via attach_ovstage(). Replication runs in the internal representation only (USD untouched).

Cross-environment collision filtering can optionally use PhysX environment ids, controlled by the /ovphysx/clone/useEnvIds setting (default: on). When enabled and the scene runs GPU dynamics + GPU broadphase, each cloned environment gets a distinct environment id so copies in different environments do not collide. The source environment is included: its bodies are created holding environment id 0 (assigned as the attach parses them; clones get 1..N), so co-located clones (anchor_transforms=None) are collision-isolated from the source as well. Environment ids do not provide collision isolation in CPU mode. Give CPU clones spatially disjoint anchor_transforms. Otherwise all copies share one collision space. The runtime logs a warning when env ids are requested but GPU dynamics or GPU broadphase is unavailable. Call ovphysx.enable_python_logging() to receive it on the ovphysx Python logger. Like all carbonite settings, useEnvIds is per-process (shared by every ovphysx instance in the process), so set it consistently before attaching.

When one logical environment is assembled from SEVERAL clone calls (e.g. an IsaacLab ClonePlan cloning one source row at a time: first /env0/Robot to every environment, then /env0/Object), pass env_ids so objects that share an environment share an environment id. With env_ids=None each call numbers its copies afresh, so /env1/Robot and /env1/Object cloned by different calls would land on different ids and never collide with each other:

def clone_environment_parts(physx):
    env_ids = [0, 1]  # same ids in every call -> same environments
    physx.clone("/env0/Robot", ["/env1/Robot", "/env2/Robot"], env_ids=env_ids)
    physx.clone("/env0/Object", ["/env1/Object", "/env2/Object"], env_ids=env_ids)
    physx.wait_all()
Parameters:
  • source_path – USD path of the source prim hierarchy to clone (e.g., “/World/env0”)

  • target_paths – Runtime physics-object paths for the cloned hierarchies (e.g., [“/World/env1”, “/World/env2”])

  • anchor_transforms – Optional list of (px, py, pz, qx, qy, qz, qw) transforms giving the absolute world pose of each target subtree root. Entry i anchors the exact subtree at target_paths[i]. Position is followed by quaternion rotation (imaginary-first, matching tensor API convention). Identity rotation = (0, 0, 0, 1). Must have the same length as target_paths. Descendants keep their poses relative to the source subtree root: target_object_world = anchor_transforms[i] * inverse(source_root_world) * source_object_world. Pass None to co-locate every copy on the source. Co-location is collision-isolated only under GPU dynamics + GPU broadphase. In CPU mode, provide spatially disjoint transforms to avoid cross-environment collisions.

  • env_ids – Optional logical environment id per target (list of int, same length as target_paths, each 0 <= id < 0x00FFFFFF, because PhysX supports at most 1<<24 environments and the runtime id is env_ids[i] + 1). Stable across calls: the same id always maps to the same runtime environment, so clones from different calls that share an id collide with each other and stay isolated from every other environment (engages under GPU dynamics + GPU broadphase, like all env-id filtering). Pass None for automatic per-call numbering (each call’s copies get fresh ids past every previous call’s).

Returns:

Immutable Task receipt for use with wait_task().

Raises:
  • ValueError – If paths are invalid, anchor_transforms has the wrong length or contains an invalid pose, or env_ids has the wrong length or contains an invalid id.

  • RuntimeError – If clone fails to queue, if no ovstage Stage is attached, or if clone() is called after warmup() or the first step() / step_sync(). Cloning after warmup corrupts simulation state on GPU and is rejected in all modes for API consistency. To recover, call detach_ovstage(), wait for it to complete, then reload the source scene or reattach its ovstage before cloning again.

Preconditions:
  • An ovstage Stage is attached and source_path names physics to clone.

  • target_paths are unique and do not already exist.

  • warmup() has not been called and no step() / step_sync() has run since the current stage was attached.

Side effects:
  • Creates live PhysX objects keyed by the target paths. No USD or runtime-stage prims are authored.

Ownership/Lifetime:
  • Clones remain valid until detach_ovstage().

Threading:
  • Do not call concurrently on the same instance without external sync.

Errors:
  • Raises ValueError for invalid inputs.

  • Raises RuntimeError when submission is rejected, including duplicate-target and after-step/after-warmup ordering violations.

  • Accepted execution failures raise TaskError when collected by a wait.

create_contact_binding(
sensor_patterns: list[str],
filter_patterns: list[str] | None = None,
filters_per_sensor: int = 0,
max_contact_data_count: int = 0,
) → ContactBinding#

Create a contact binding for reading aggregate and detailed contact tensors.

Deprecated since version 0.6.0: Contact bindings are deprecated.

Returns DLPack-compatible tensors of net forces [S, 3] or force matrices [S, F, 3]. Detailed contact and friction data are exposed as flat [C, ...] buffers plus [S, F] count/start-index tensors via ContactBinding.read_normal_contact_data() and ContactBinding.read_friction_contact_data().

A sensor is a set of rigid bodies matched by a physics-object path pattern. A filter is a second set of bodies whose contacts with each sensor you want to measure. Patterns include authored USD objects and runtime-only clones.

Sensor selection is opt-in: every authored USD prim matched by sensor_patterns must have PhysxContactReportAPI applied, on the prim named as the sensor itself (not a parent body or child collider). A matched prim without the schema is dropped from the binding, and if that leaves no sensors this call raises RuntimeError. Filter prims need no extra schema. Runtime-only clones use the schema metadata copied from the corresponding source object: a cloned collider whose source collider lacks the schema is rejected even if its parent body has it.

On CPU simulation and GPU dynamics with CPU readback, a separate child collider’s schema enables sensor selection, not reporting for its owning body. Also enable reporting on the body, owning articulation link, or articulation root to avoid depending on reports from the other actor in each pair. If neither actor reports matching contacts, the child sensor reads zero. Configure reporting settings on the reporting actor or articulation root; a standalone static collider is its own actor.

In these modes, enable owner reporting but select only the child as a binding sensor. If the owner is also selected as a sensor in this or another live contact binding on the same attachment, the owner takes precedence: contacts are credited to the owner and the child reads zero. Check wildcard patterns for unintended owner matches, and establish bindings before stepping. Session reads support selecting both the owner and child in these modes.

On DirectGPU, a separate child collider carrying PhysxContactReportAPI is accepted by the deprecated contact binding, but the runtime logs an unsupported collider warning and the child reads zero force. DirectGPU session queries omit that child row; select the owning body or articulation link instead.

The binding must be created before the first simulation step whose contacts you want to observe. Call ContactBinding.read_net_normal_forces() or ContactBinding.read_normal_force_matrix() after a successful PhysX.step() or PhysX.step_sync() call. Before the first step, both return all-zeros tensors.

Result tensor shapes after step:
  • net forces: [S, 3] where S = matched sensor count

  • force matrix: [S, F, 3] where F = matched filter count per sensor

  • detailed data: flat [C, 1] or [C, 3] buffers indexed by counts and start_indices with shape [S, F]

Use ContactBinding.sensor_paths and ContactBinding.filter_paths to map rows and columns back to resolved physics-object paths.

Example:

import torch

def read_contact_forces(physx):
    with physx.create_contact_binding(
        sensor_patterns=["/World/robot_0/ee"],
        filter_patterns=["/World/obstacles/box"],
        filters_per_sensor=1,
        max_contact_data_count=256,
    ) as binding:
        # Call this after a successful simulation step.
        forces = torch.zeros(
            (binding.sensor_count, 3), device="cuda"
        )
        binding.read_net_normal_forces(forces)
        return forces
Parameters:
  • sensor_patterns – Physics-object path patterns for sensor bodies. A single path component may be at most 4096 characters long; a longer one raises RuntimeError (also for filter_patterns). The matching rules are on the “Path patterns” page of the ovphysx documentation.

  • filter_patterns – Flat list of physics-object path patterns for filters. Total length must equal len(sensor_patterns) * filters_per_sensor. Pass None with filters_per_sensor=0 to get contacts with all bodies.

  • filters_per_sensor – Number of filter patterns per sensor (same for all sensors).

  • max_contact_data_count – Max raw contact pairs to track in the native backend. Also caps the detailed contact/friction flat-buffer reads. Detailed reads require this value and filters_per_sensor to be positive.

create_sdf_view(
pattern: str,
max_query_points: int,
) → SdfView#

Create an SDF shape view for evaluating signed distance fields.

Deprecated since version 0.6.0: SDF views are deprecated. Use evaluate_sdf_shapes(), which evaluates the same shapes through an SDF_SHAPE output query and takes Q from the arrays on every call.

Requires a GPU instance. CPU SDF evaluation is not implemented.

Parameters:
  • pattern – Physics-object path pattern matching SDF collision shapes, including runtime-only clones. A single path component may be at most 4096 characters long; a longer one raises RuntimeError. The matching rules are on the “Path patterns” page of the ovphysx documentation.

  • max_query_points – Number of query points per shape per call. Query tensors passed to SdfView.evaluate must have Q equal to this.

Returns:

SdfView with count == number of matched shapes.

Example:

sdf = physx.create_sdf_view("/World/Mesh*", max_query_points=64)
# Query/output tensors must be on the CUDA device (SDF eval is GPU-only).
pts = torch.zeros((sdf.count, 64, 3), dtype=torch.float32, device="cuda")
out = torch.zeros((sdf.count, 64, 4), dtype=torch.float32, device="cuda")
sdf.evaluate(pts, out)
sdf.destroy()
create_tensor_binding(
pattern: str = None,
prim_paths: list[str] = None,
tensor_type: int = TensorType.RIGID_BODY_POSE,
*,
raise_if_empty: bool = False,
) → TensorBinding#

Create tensor binding for bulk physics data access (synchronous).

Deprecated since version 0.6.0: The tensor-binding API is deprecated. Use PhysX.read() for reads and PhysX.write() for writes.

A tensor binding connects physics objects (by path pattern or explicit paths) to a tensor type, including authored USD objects and runtime-only clones.

Parameters:
  • pattern – Physics-object path pattern (e.g., “/World/robot*”, “/World/env[0-9]/robot”; [N] is not an index placeholder, it matches the letter N). The matching rules are on the “Path patterns” page of the ovphysx documentation. A single path component (the text between two slashes; a parenthesized group counts as one component even if it contains a slash) may be at most 4096 characters long; a longer component is rejected with RuntimeError. Mutually exclusive with prim_paths.

  • prim_paths – Explicit list of physics-object paths. Mutually exclusive with pattern.

  • tensor_type – Tensor type enum value (TensorType.*).

  • raise_if_empty – If True, raise ValueError when the binding matches zero physics objects. The default keeps empty bindings valid. Prefer it for optional or broad queries and check binding.count.

Returns:

TensorBinding object for reading/writing tensor data.

Raises:
  • ValueError – If neither pattern nor prim_paths is provided, both are, or raise_if_empty is true and no physics objects match.

  • RuntimeError – If binding creation fails.

Examples:

import numpy as np
from ovphysx import TensorType

def use_tensor_bindings(physx):
    # Optional broad queries can be empty.
    with physx.create_tensor_binding(
        "/World/robot*", tensor_type=TensorType.RIGID_BODY_POSE
    ) as binding:
        if binding.count:
            poses = np.zeros(
                binding.shape, dtype=np.dtype(str(binding.dtype))
            )
            binding.read(poses)

    binding = physx.create_tensor_binding(
        prim_paths=["/World/env1/robot", "/World/env2/robot"],
        tensor_type=TensorType.ARTICULATION_DOF_POSITION_TARGET,
    )
    targets = np.zeros(
        binding.shape, dtype=np.dtype(str(binding.dtype))
    )
    binding.write(targets)
    binding.destroy()
Preconditions:
  • Exactly one of pattern or prim_paths must be provided.

  • A USD stage is loaded.

Side effects:
  • Allocates native binding resources.

Ownership/Lifetime:
  • Returned TensorBinding retains native resources until destroy(). Each call returns an independent handle; destroying one binding does not invalidate a sibling selecting the same objects.

  • A new binding selects the currently eligible realized objects, even while an older binding for the same pattern remains alive.

  • Use binding.shape and binding.dtype (or binding.spec) for layout and binding.native_device for no-staging placement. Most tensor types are float32, but some types such as RIGID_BODY_DISABLE_SIMULATION are not.

  • The binding is tied to the current stage topology. Reuse it across steps, but do not keep it across detach_ovstage(), removing USD data that contains bound objects, or replacing/reparsing the stage so bound objects are destroyed and recreated. Destroy cached bindings before those lifecycle operations when practical. If a stale binding survives, only destroy it. Create replacements after the operation completes.

Diagnostics:
  • Pattern bindings can intentionally match zero physics objects, so expected TensorAPI no-match diagnostics are quieted on the simulation view used to create that binding.

  • Explicit prim_paths keep the default error-level no-match diagnostics for typo detection. To detect partial misses programmatically, compare the requested prim_paths with the resolved binding.prim_paths returned after creation.

Threading:
  • Do not create bindings concurrently with stage mutation.

Errors:
  • Raises ValueError for invalid arguments.

  • Raises RuntimeError on creation failure.

destroy() → None#

Destroy this PhysX instance.

Preconditions:
  • No other thread is using this instance. Calling destroy() again after terminal destruction is a valid no-op.

Side effects:
  • Releases native resources and unregisters the instance.

  • Collects all outstanding raw tasks and session operations, including step and clone receipts. They cannot be collected again afterward.

Ownership/Lifetime:
  • All tensor bindings and contact bindings created by this instance are automatically released.

  • Object-change subscriptions and their Python callback captures are released after native subscription cleanup.

  • Drop every output-read Warp array and downstream view before destruction. Live aliases cause RuntimeError before teardown; the instance and arrays stay valid so destruction can be retried after dropping the aliases.

  • The instance becomes unusable after destruction.

Threading:
  • Do not call concurrently with other operations on this instance.

Errors:
  • Reports collected task and cleanup failures after attempting teardown; a TaskError can therefore be raised after the instance is destroyed.

  • Raises RuntimeError without changing the instance if called from a native log callback. Retry after the callback returns.

  • Raises RuntimeError and preserves ownership when native destruction returns INVALID_STATE because companion leases or a runtime/recording transition remain active. Close leases or finish the transition, then retry.

  • Other native destruction failures or process shutdown failures raise RuntimeError after terminal destruction; a later call is a no-op. If both fail, the process-shutdown error is reported with the native status included.

  • A Python or ctypes exception raised while invoking native destruction leaves ownership intact so the call can be retried.

  • Because this is a checked operation, a cleanup failure raised from a finally block becomes the active exception. Python preserves any in-flight exception as chained context; applications that need different precedence must catch and log cleanup failures explicitly.

detach_ovstage() → Task#

Submit Stage teardown and return its Task receipt.

Execution currently runs inline. Earlier tasks complete before teardown, but their outcomes remain uncollected. Collect this Task with wait_task(), or use wait_all() to collect every pending outcome. Wait for successful teardown before destroying the Stage. Detaching an unattached instance succeeds as a no-op task. Detach does not restore initial poses or reset simulation time. Clears registered interests and output-buffer registrations, so a subsequent attach_ovstage() to a different Stage starts clean. After detach, stage-dependent calls such as update_from_ovstage() and step() fail until a Stage is attached again. Detach invalidates the stage’s tensor, contact, and SDF views. Do not read, write, or evaluate existing bindings or SDF views. Destroy them and create replacements after calling attach_ovstage() and realizing a stage again. If this instance owns an active OVD recording, detach stops and finalizes it. Reattach stays dormant until an explicit recording start, which may occur before the next simulation step.

Errors:
  • Raises RuntimeError if submission or Python cleanup is rejected.

  • Accepted execution failures raise TaskError when collected. Teardown may partially retire resources on failure. The Stage remains retained while native ownership remains attached.

evaluate_sdf_shapes(
points,
out,
*,
prim_paths: list[int] | None = None,
pattern: str | None = None,
cuda_stream: int = 0,
cuda_wait_event: int = 0,
) → None#

Evaluate the signed distance fields of SDF collision shapes at the given points.

The successor of create_sdf_view() and SdfView.evaluate(). The shapes are the members of an SDF_SHAPE output query: the collision shapes the SDF view accepts, a collider carrying PhysxSDFMeshCollisionAPI whose shape is a triangle mesh with an SDF, runtime clones included. Rows follow the selection: prim_paths in the order given, pattern in the same match order as create_sdf_view(); with neither, every SDF shape, in the order the runtime stores them. A selected prim that is not an SDF shape is skipped, as the SDF view skipped it.

For each row i and point j, out[i, j] receives the gradient (x, y, z) and then the signed distance at points[i, j], negative inside. Points and gradients are in each shape’s mesh-local space (the unscaled frame of the mesh’s vertices); no transform is applied. Q, the points per shape, is read from the arrays on every call. A point outside the shape’s SDF grid (the mesh bounds padded by the SDF margin) is evaluated, not refused, as by the SDF view: its distance is the SDF value at the nearest grid point plus the distance to the grid, a positive upper bound, and its gradient points away from the shape. This waits for the evaluation, so out is complete when it returns.

Requires a GPU instance (DirectGPU). The first evaluation after loading USD may perform the automatic DirectGPU warmup step, as the SDF view did. After that it never steps: the scene must have simulated since physics objects were last created or released, as PhysX uploads shape data to the GPU only when it simulates, so step once after such a change.

Parameters:
  • points – DLPack-compatible float32 array of shape [N, Q, 3] on the CUDA device, N the number of selected SDF shapes.

  • out – Pre-allocated DLPack-compatible float32 array of shape [N, Q, 4] on the same device.

  • prim_paths – Optional native ovx_primpath_t handles naming the shapes, from the attached Stage’s path dictionary as for query(). Takes precedence over pattern.

  • pattern – Optional absolute path pattern naming the shapes, matched as in query(); the complete rules are on the “Path patterns” page of the ovphysx documentation.

  • cuda_stream – Producer stream of points still writing them, drained before they are read, as for WriteSession.commit(). Warp arrays and CUDA DLPack producers are synchronized already. Stream 1 names the legacy default stream of the current CUDA context.

  • cuda_wait_event – Producer completion event of points, waited on before they are read. out must have no outstanding device reads or writes when the call is made, unless that work is on cuda_stream or before cuda_wait_event; nothing else may use out until it returns.

Raises:
  • ValueError – If pattern is empty, or an array is not C-contiguous.

  • RuntimeError – If an array has the wrong dtype, shape or device, N is not the number of selected SDF shapes (the message states it) or exceeds 65535, N x Q exceeds 2^31 - 1, the instance is not DirectGPU, the scene has not simulated since physics objects last changed, the producer handoff fails, or the evaluation fails.

get_config(
key: ConfigKey,
) → bool | int | float | str | None#

Return one value retained by this instance, or None when unset.

static get_cpu_mode() → bool#

Compatibility wrapper returning effective hard CPU-only mode.

True when PhysX.set_cpu_mode(True) has succeeded, or when OVPHYSX_DISABLE_GPU is active. The environment variable is read live before ovphysx_initialize (and again after shutdown until the next initialize). Initialize latches it for that interval. This is not a query of per-scene USD physxScene:enableGPUDynamics, a CUDA ordinal (active_cuda_gpus), or attach-time resolved dynamics.

Callable at any time. No PhysX instance is required.

get_object_type(prim_path: str) → ObjectType#

Classify an authored USD prim by TensorAPI object type.

Deprecated since version 0.6.0: Object-type lookup is deprecated.

See ObjectType for the taxonomy. Paths with no classified simulation object return ObjectType.INVALID with success. The call did not fail, the path is not a known simulation object. Live standalone, custom, and articulation joints at their authored prim paths must not return ObjectType.INVALID.

Raises RuntimeError for invalid input (empty path, embedded NUL byte) or if no stage is attached.

Returns:

One of RIGID_BODY, ARTICULATION, ARTICULATION_LINK, ARTICULATION_ROOT_LINK, ARTICULATION_JOINT, JOINT, CUSTOM_JOINT, or INVALID.

Return type:

ObjectType

get_scene_query_paths_from_ids(ids: tuple | list) → list[str]#

Resolve scene-query hit identity fields to physics-object paths.

Deprecated since version 0.6.0: Scene queries are deprecated.

ids holds opaque identity handles taken directly from the collision, rigid_body, or material entries of hit dicts returned by raycast(), sweep(), or overlap(). IDs that cannot be resolved (a zero id, an id from an object removed since the query, or no active attach) yield empty strings.

Parameters:

ids – Sequence of int identity handles.

Returns:

Physics-object paths in the same order as ids.

Return type:

list[str]

property handle: int#

The raw ovphysx_instance_handle_t for this instance (read-only).

Use this when passing the handle to C/C++ code that calls the ovphysx C API directly.

Raises:

RuntimeError – If the instance has been destroyed.

is_recording() → bool#

Return True only while this instance owns active sampling.

A peer reports False while another instance owns a session.

is_stage_attached(stage=None) → bool#

Return native attachment state, including changes made by native callers.

With stage supplied, also check that native code still holds that caller-owned Stage (or raw pointer). This is not a resource-validity check. The snapshot is synchronous and neither waits for nor collects tasks. Wait for a pending lifecycle task before interpreting its final state; a false snapshot does not permit destroying a pending attach’s Stage. Output caches check their original attachment separately to detect same-stage reattachment.

overlap(
geometry_type: SceneQueryGeometryType,
mode: SceneQueryMode = SceneQueryMode.ALL,
**kwargs,
) → list[dict]#

Test geometry overlap against objects in the scene.

Deprecated since version 0.6.0: Scene queries are deprecated.

For overlap queries, location fields (normal, position, distance, face_index, material) are zeroed. Only object identity is populated.

Parameters:
  • geometry_type – SceneQueryGeometryType.

  • mode – SceneQueryMode (ANY or ALL).

  • **kwargs – Geometry parameters (same as sweep()).

Returns:

List of hit dicts (same format as raycast()).

Raises:

ValueError – If mode is CLOSEST.

query(
object_type: SimObjectType,
*,
scope: ObjectScope = ObjectScope.ALL,
prim_paths=None,
pattern=None,
contacts=None,
metadata: bool = True,
) → Operation[Query]#

Submit a reusable selector. Handles and metadata require successful completion.

Explicit prim handles take precedence over a pattern. Selections use ALL scope and keep their resolved membership; a whole-type ACTIVE selector is reevaluated when a session opens. Metadata is a creation-time snapshot; use metadata=False to omit optional discovery work. contacts selects CONTACT_SENSOR rows and optional paired filters through ContactSelection; it cannot be combined with prim_paths, pattern, or ACTIVE scope. DEBUG_RENDER is this instance’s target: it needs no attached stage, and prim_paths, pattern, and contacts do not apply. Its scope is validated and then ignored.

raycast(
origin: tuple | list,
direction: tuple | list,
distance: float,
mode: SceneQueryMode = SceneQueryMode.CLOSEST,
both_sides: bool = False,
) → list[dict]#

Cast a ray and return hits.

Deprecated since version 0.6.0: Scene queries are deprecated.

Parameters:
  • origin – Ray origin [x, y, z].

  • direction – Normalized ray direction [x, y, z].

  • distance – Maximum ray length (>= 0).

  • mode – SceneQueryMode (CLOSEST, ANY, or ALL).

  • both_sides – If True, test both sides of mesh triangles.

Returns:

List of hit dicts. Each dict contains collision, rigid_body, proto_index, normal, position, distance, face_index, material. For ANY mode, hit fields are zeroed.

read(
query: Query,
attributes,
*,
metadata: bool = False,
) → Operation[ReadResult]#

Submit a read-session open using a completed Query, without fetching.

Attributes are names or tokens from the owning Stage dictionary. Optional metadata describes availability at open; None never causes a later fetch. Use session.fetch_next().wait() to materialize a group on the current Warp stream. Native host completion does not synchronize unrelated CUDA streams.

Availability is per attribute and scene. Simulated DirectGPU columns need the first simulation step. isSleeping is a CPU uint8 snapshot (1 asleep, 0 awake); links report their articulation’s state. DirectGPU disables sleeping, so emitted values are 0 and its existing step-first and disabled body omission rules apply. Use an ALL-scope query to include sleeping bodies on modes that support sleep.

read_sync(
object_type: SimObjectType,
attribute_names,
*,
scope=ObjectScope.ALL,
prim_paths=None,
pattern=None,
contacts=None,
metadata: bool = False,
) → ReadResult#

Explicit waiting convenience: open an internal query and fetch every group.

read_tokens_sync(
object_type: SimObjectType,
attribute_tokens,
*,
scope=ObjectScope.ALL,
prim_paths=None,
pattern=None,
contacts=None,
metadata: bool = False,
) → ReadResult#

Explicit waiting convenience for attributes from the owning Stage dictionary.

set_config(
key: ConfigKey,
value: bool | int | float | str,
) → None#

Set one value retained by this instance.

static set_cpu_mode(cpu_only: bool) → None#

Compatibility wrapper for GlobalConfigKey.CPU_ONLY.

Call before the first PhysX instance is ever created to keep ovphysx’s own code from touching CUDA. The call requires no active instances. Once set to True successfully, the mode cannot be reversed for this process.

When called before the first instance, True prevents CUDA driver use by ovphysx and makes all PhysX scenes use CPU dynamics regardless of their USD physxScene:enableGPUDynamics settings. Other libraries in the process may still open the driver. A call after an earlier instance was destroyed may succeed, but cannot provide ovphysx’s no-CUDA-touch guarantee or retarget an already-bootstrapped runtime. For CPU-only deployments, setting OVPHYSX_DISABLE_GPU before ovphysx initialization provides the equivalent process-wide policy.

Raises:

RuntimeError – If any PhysX instances are currently active, or if attempting to set False after True has been applied (CPU-only mode is sticky as soon as enabling it succeeds).

start_recording(destination: OmniPvdDestination) → None#

Start an explicit OVD recording session.

Make the shared runtime OVD recording capable before the first PhysX() by calling set_global_config(GlobalConfigKey.OVD_RECORDING_CAPABLE, True). The key defaults to false; capability alone does not start output. Attach a physics stage before calling this method; recording may start before the first simulation step. Creation and attachment stay dormant. Any PhysX instance sharing a capable runtime may start a session while none is active; that instance then owns it. A runtime created without capability rejects start with INVALID_STATE and an error naming the capability key. Unsupported platforms retain NOT_IMPLEMENTED.

A failed validation or destination-open attempt may be retried. A start while recording is active is invalid and does not replace its destination. After stop, another FILE or TCP session may be started.

step(dt: float) → Task#

Initiate a physics step and return its Task receipt.

Simulation time is tracked internally. Each step advances it by dt. The timestep is passed through without clamping or substepping; choose a timestep appropriate for the simulation.

A dt of 0.0 is accepted but simulates nothing: it advances no simulation time and leaves all state, including the contacts and timestep that contact reads use, exactly as the previous step left them.

Parameters:

dt – Finite, nonnegative delta time in seconds.

Returns:

Immutable Task receipt for use with wait_task().

Example:

def step_and_collect(physx):
    task = physx.step(0.016)
    physx.wait_task(task)
Preconditions:
  • An ovstage Stage is attached to this instance.

Side effects:
  • Advances simulation time and mutates physics state.

Ownership/Lifetime:
  • The receipt owns no simulation resources. A terminal outcome is collected once by wait_task() or wait_all().

Threading:
  • Do not call concurrently on the same instance without external sync.

Errors:
  • Raises RuntimeError on failure to enqueue.

  • Accepted execution failures raise TaskError when collected by a wait.

step_sync(dt: float) → None#

Step simulation and wait for completion in a single call.

Faster than step() + wait_task() for performance-critical applications like RL training that always wait immediately. Simulation time is tracked internally and advanced by dt.

A dt of 0.0 simulates nothing, exactly as in step().

Parameters:

dt – Finite, nonnegative delta time [s], passed through as in step().

Raises:

RuntimeError – If the step or wait fails.

stop_recording() → None#

Stop and finalize the OVD recording owned by this instance.

Peer instances cannot stop another owner’s session.

subscribe_object_changes(
*,
on_created=None,
on_destroyed=None,
on_all_destroyed=None,
) → int#

Subscribe this instance to PhysX object create/destroy notifications.

Returns a subscription id for unsubscribe_object_changes(). Callbacks fire only while this instance’s own attachment is live.

sweep(
geometry_type: SceneQueryGeometryType,
direction: tuple | list,
distance: float,
mode: SceneQueryMode = SceneQueryMode.CLOSEST,
both_sides: bool = False,
**kwargs,
) → list[dict]#

Sweep a geometry shape along a direction and return hits.

Deprecated since version 0.6.0: Scene queries are deprecated.

Parameters:
  • geometry_type – SceneQueryGeometryType.

  • direction – Normalized sweep direction [x, y, z].

  • distance – Maximum sweep distance (>= 0).

  • mode – SceneQueryMode.

  • both_sides – If True, test both sides of mesh triangles.

  • **kwargs –

    Geometry parameters:

    • SPHERE: radius, position

    • BOX: half_extent, position, rotation (xyzw quaternion)

    • SHAPE: prim_path (USD prim path string)

Returns:

List of hit dicts (same format as raycast()).

unsubscribe_object_changes(subscription_id: int) → None#

Stop object-change notifications for a subscription this instance owns.

Returns only after in-flight callbacks for that subscription have finished. Calling it from inside any object-change callback raises RuntimeError and leaves the subscription active. That check follows the Carbonite task when the callback is running as one, and the native thread otherwise.

update_articulations_kinematic(
*,
flags: ArticulationKinematicFlag = ArticulationKinematicFlag.POSITION | ArticulationKinematicFlag.VELOCITY,
scope: ObjectScope = ObjectScope.ALL,
prim_paths: list[int] | None = None,
pattern: str | None = None,
) → None#

Update selected articulation link state from current generalized state.

The articulations updated are the members of an ARTICULATION output query: every articulation in scope, or only those a prim_paths / pattern selection names, with the same selection rules as query(). Articulations outside the selection are left unchanged. This waits for the query and forward-kinematics tasks and raises any execution failure. It returns None after updating link poses and/or velocities without running a normal simulation step, collision detection, or contact generation.

In GPU mode, the first kinematic update after loading USD may perform the same automatic DirectGPU warmup step used by tensor reads/writes.

Parameters:
  • flags – POSITION, VELOCITY, or both. Zero validates the query and does no update.

  • scope – ALL articulations or the current ACTIVE articulation set. A selection has no scope, so combining prim_paths or pattern with ACTIVE raises ValueError.

  • prim_paths – Optional native ovx_primpath_t handles naming the articulations to update, from the attached Stage’s path dictionary as for query(). A handle of an articulation’s link or joint selects that articulation. Takes precedence over pattern.

  • pattern – Optional absolute path pattern naming the articulations to update, matched as in query(); the complete rules are on the “Path patterns” page of the ovphysx documentation.

Raises:
  • ValueError – If a selection is combined with scope=ACTIVE, or pattern is empty.

  • RuntimeError – If the update fails.

update_from_ovstage(
from_ordinal: int,
to_ordinal: int,
) → Task#

Submit committed edits over [from_ordinal, to_ordinal] and return a Task.

The application that writes to ovstage owns the ordinal range and calls this after sealing the writes. population.apply_usd_changes() waits for population work but does not seal its ordinal; complete stage.advance_write_floor(ordinal).wait() before this call. ovphysx forwards the range (as ovstage’s own ovstage_ordinal_range_t) to the runtime ovstage change feed and applies the resulting deltas to the simulation.

Ordinals at or below the latest successfully consumed ordinal are skipped. A fully consumed range succeeds as a no-op. An overlapping range applies only its unread suffix. attach_ovstage() consumes its initial read_ordinal, so replaying it does not repeat initial population events. Later authored and sealed population changes are applied normally.

Execution currently runs inline. Collect the Task with wait_task() or wait_all() to observe execution failure before relying on the updated state. Submission errors raise RuntimeError immediately; accepted execution failures raise TaskError at collection. Keep the sealed data readable until completion.

wait_all(*, timeout_ns: int | None = None) → None#

Collect uncollected tasks accepted before this call began.

Tasks are collected in submission order with one readiness deadline. Completed successes and failures are collected once. A timeout stops at the earliest unfinished task, leaving it and later tasks uncollected. Failures remain reportable even when their original receipts were discarded.

Parameters:

timeout_ns – Readiness timeout in nanoseconds, with the same semantics as wait_task(). None waits indefinitely; 0 polls once.

Returns:

None on success, including an empty or already-collected task set.

Raises:
  • ValueError – If timeout_ns is outside 0 through 2**64 - 1.

  • TaskError – If collected tasks failed. The errors property contains immutable (Task, message) entries with copied text.

  • TaskTimeoutError – If work remains unfinished at the deadline, even when earlier tasks failed. The errors property contains those earlier failures; pending_task identifies the earliest unfinished task. Collected failures are not repeated by later waits.

  • RuntimeError – If the instance is invalid or the wait itself fails.

Serialize calls on each instance externally.

wait_task(
task: Task,
*,
timeout_ns: int | None = None,
) → None#

Wait for and collect only the supplied task’s terminal outcome.

Parameters:
  • task – Task receipt returned by this instance.

  • timeout_ns – Readiness timeout in nanoseconds. None waits indefinitely; 0 polls once. Finalization after readiness can exceed the timeout.

Returns:

None on success.

Raises:
  • TypeError – If task is not a Task.

  • ValueError – If timeout_ns is outside 0 through 2**64 - 1.

  • TaskError – If this task failed. The exception owns copied error text.

  • TaskTimeoutError – If the task is unfinished at the deadline. Its pending_task remains available for another wait.

  • RuntimeError – If the instance or receipt is invalid, the task was already collected, or the wait itself fails.

Waiting for B never reports or collects A’s failure. A completed outcome can be collected once; internal synchronization does not collect it. Serialize calls on each instance externally.

Example:

from ovphysx import TaskTimeoutError

def poll_task(physx, task):
    try:
        physx.wait_task(task, timeout_ns=0)
    except TaskTimeoutError:
        return False
    return True
warmup() → None#

Explicitly run the warmup step (synchronous).

On first call, runs a minimal simulation step (~1ns) to initialize PhysX structures. Works in both CPU and GPU mode (in GPU mode this also populates DirectGPU buffers).

Normally done automatically on the first tensor read, but calling it explicitly lets you control when the latency occurs.

This function is idempotent. Calling it multiple times has no effect after the first successful call. Warmup state resets after detach_ovstage() or attaching a new USD stage.

Raises:

RuntimeError – If warmup fails.

Side effects:
  • Advances simulation by a minimal timestep on first call.

Threading:
  • Do not call concurrently with other operations on this instance.

write(
query: Query,
attributes,
*,
metadata: bool = False,
) → Operation[WriteSession]#

Submit one multi-attribute write-session open using a completed Query.

Open validates every requested writable attribute before exposing groups. It publishes no values. Fetch indices refer to the original request order; each commit has its own task and may fail after earlier commits applied.

write_sync(
object_type: SimObjectType,
attributes,
*,
scope=ObjectScope.ALL,
prim_paths=None,
pattern=None,
metadata: bool = False,
values=None,
) → WriteSession#

Explicit waiting convenience; a single name or an attribute sequence is accepted.

values fills a debug-render scope or cullingBox buffer before return.

class ovphysx.api.TensorBinding(
sdk,
handle: int,
tensor_type: int,
ndim: int,
shape: tuple,
dtype: DLDataType | None = None,
*,
_from_factory: bool = False,
)#

Bases: object

Tensor binding for bulk physics data access via DLPack.

Deprecated since version 0.6.0: The tensor-binding API is deprecated. Use PhysX.read() for reads and PhysX.write() for writes.

A tensor binding connects a physics-object path pattern to a tensor type, enabling efficient bulk read/write for authored USD objects and runtime-only clones (poses, velocities, joint positions, etc.). The shape, ndim, and dtype metadata come from ovphysx_get_tensor_binding_spec(). Use them to allocate compatible buffers instead of assuming every tensor type is float32. Use native_device to choose the no-staging CPU or CUDA device.

CPU-only property bindings cover standalone rigid-body mass/inertia/COM values, articulation DOF/body properties, rigid-body/articulation shape properties, deformable-material properties, and disable-simulation/gravity flags. Fixed and spatial tendon property bindings are not CPU-only. CPU-only property bindings require host-resident tensor, index, and mask buffers, including when the simulation runs on GPU.

This is a synchronous API - operations complete before returning. Bindings are tied to the currently realized physics objects. Reuse them across simulation steps, but do not keep them across detach_ovstage(), removing USD data that contains bound objects, or replacing/reparsing the stage so bound objects are destroyed and recreated. Destroy cached bindings before those lifecycle operations when practical. If a stale binding survives, only destroy it. Create replacement bindings after the operation completes.

Usage patterns:

  • Context manager (auto-cleanup):

    import numpy as np
    from ovphysx import TensorType
    
    def raise_robot_poses(physx):
        with physx.create_tensor_binding(
            "/World/robot*", tensor_type=TensorType.RIGID_BODY_POSE
        ) as binding:
            poses = np.zeros(binding.shape, dtype=np.dtype(str(binding.dtype)))
            binding.read(poses)
            poses[:, 2] += 0.1  # raise z position
            binding.write(poses)
        # Auto-destroyed here
    
  • Manual (explicit cleanup):

    import numpy as np
    from ovphysx import TensorType
    
    def read_robot_poses(physx):
        binding = physx.create_tensor_binding(
            "/World/robot*", tensor_type=TensorType.RIGID_BODY_POSE
        )
        poses = np.zeros(binding.shape, dtype=np.dtype(str(binding.dtype)))
        binding.read(poses)
        binding.destroy()
        return poses
    
property body_count: int#

Number of links.

property body_names: list[str]#

List of body/link names.

property count: int#

Get number of entities (first dimension of shape).

destroy() → None#

Release binding resources.

Safe to call multiple times. Called automatically on garbage collection or when exiting a context manager.

Preconditions:
  • Binding must not be in use by other threads.

Side effects:
  • Releases native resources and invalidates the binding.

Ownership/Lifetime:
  • After destruction, the binding cannot be used.

Threading:
  • Serialized per binding via an internal lock.

Errors:
  • RuntimeError if destruction fails.

property dof_count: int#

Number of degrees of freedom (DOFs). 0 if not an articulation binding.

property dof_names: list[str]#

List of DOF names (one per DOF).

property dtype: DLDataType#

Get the required DLPack dtype for tensors passed to this binding.

Most bindings use float32. Index bindings (deformable element indices) use int32. The bool bindings (DISABLE_SIMULATION, DISABLE_GRAVITY) use uint8, as does ARTICULATION_DOF_DRIVE_TYPE, which is a per-DOF enum byte rather than a flag. See dtype_name for a compact string form.

property dtype_name: str#

Get the required tensor dtype as a short string such as float32, int32, or uint8.

property fixed_tendon_count: int#

Number of fixed tendons per articulation (0 if none).

Use to decide whether to allocate buffers for fixed tendon property tensors (types 80-85) and to skip tendon code paths when T=0.

property handle: int#

Get the binding handle.

property is_fixed_base: bool#

Whether the articulation has a fixed base.

property joint_count: int#

Number of joints per articulation.

property joint_names: list[str]#

List of joint names.

property native_device: DLDevice#

Get the binding’s native DLPack device.

Deprecated since version 0.6.0: The tensor-binding API is deprecated. Use PhysX.read() for reads and PhysX.write() for writes.

CPU-only property tensors report DLDevice(kDLCPU, 0) even when the scene uses GPU dynamics. Other bindings follow their native TensorAPI view and report DLDevice(kDLCUDA, ordinal) in DirectGPU mode or DLDevice(kDLCPU, 0) otherwise. This property identifies the no-staging device and does not change existing read/write behavior. A CUDA device_id is the process-visible runtime ordinal used by a framework device such as cuda:N, not a physical PCI bus index. Compare device_type.value with a constant such as DLDeviceType.kDLCUDA. This is a live query, not cached metadata: it may wait for pending operations and rejects an invalidated simulation view.

property ndim: int#

Get the number of dimensions reported by ovphysx_get_tensor_binding_spec().

property prim_paths: list[str]#

Resolved physics-object paths in tensor row order.

Rigid-body bindings return one path per rigid-body tensor row. Articulation bindings return one root object path per articulation row. For per-articulation link names, use body_names.

read(tensor) → None#

Read simulation data into a user-provided tensor (synchronous).

The tensor must have matching shape and dtype (shape and dtype). Can be a NumPy array, PyTorch tensor, or any object with __dlpack__ protocol.

When called repeatedly with the same NumPy, PyTorch, Warp, or direct DLTensor buffer object, an internal cache reuses descriptor metadata and attribute lookups. CUDA DLPack producers still export a capsule on each call to establish stream readiness. The numpy writeable guard is preserved on the fast path. Other DLPack providers are reacquired on every call. Callers that want the fast path should reuse the same tensor object with unchanged backing storage across calls. Do not resize or rebind storage between cached calls. The staleness guard rebuilds the cache when it detects a pointer change, but storage mutations that reuse the same pointer violate the cache contract. Direct DLTensor inputs retain their caller-owned descriptor.

Parameters:

tensor – DLPack-compatible tensor with pre-allocated storage matching self.shape. Must use self.dtype. When CUDA is available, CPU/CUDA device mismatches are staged for binding types whose storage follows the simulation device. CPU-only property bindings require a host-resident tensor (kDLCPU or kDLCUDAHost), including on GPU simulations; CUDA and CUDA-managed tensors are rejected rather than staged. Cross-GPU mismatches and CUDA tensors in process-wide CPU-only mode are rejected.

Preconditions:
  • This binding is not destroyed.

  • tensor has matching shape and dtype and uses a supported device.

  • Raw DLTensor buffers must be ready for native access; callers must finish pending CUDA work on them before the call. Objects implementing the CUDA DLPack stream protocol are synchronized through Warp.

Side effects:
  • Blocks until data is available and writes into the provided tensor.

Ownership/Lifetime:
  • Caller owns tensor storage and must keep it alive for the duration of the call.

  • Do not mutate the tensor’s backing storage (resize(), set_(), etc.) between cached calls. A staleness guard detects pointer changes for NumPy, PyTorch, and Warp inputs and falls back to the slow path. Direct DLTensor inputs retain their caller-owned descriptor.

Threading:
  • Serialized per binding via an internal lock.

Errors:
  • RuntimeError if read fails (shape mismatch, device mismatch, etc.).

property shape: tuple#

Get tensor shape as tuple reported by ovphysx_get_tensor_binding_spec().

Returns:

Tensor dimensions for this binding. Scalar-property bindings use (N,). Flat state tensors use (N, C). Articulation and deformable mesh tensors use (N, L, C).

sleep(indices=None) → None#

Force rigid bodies in this binding to sleep.

Mirrors PhysX SDK PxRigidDynamic::putToSleep. Symmetric counterpart to wake_up(). Bodies that have RIGID_BODY_DISABLE_SIMULATION set are silently skipped.

Only valid on a rigid-body binding. Articulation bindings raise.

Parameters:

indices – Optional int32 DLPack-compatible tensor of indices into this binding. If None, every body in the binding is put to sleep.

Errors:

RuntimeError if the binding is destroyed, is not a rigid-body binding, has been invalidated by a stage change, or the engine call fails.

property spatial_tendon_count: int#

Number of spatial tendons per articulation (0 if none).

Use to decide whether to allocate buffers for spatial tendon property tensors (types 90-93) and to skip tendon code paths when T=0.

property spec: TensorBindingSpec#

Get a Python-owned tensor spec snapshot for this binding.

property tensor_type: int#

Get the tensor type enum value.

wake_up(indices=None) → None#

Wake rigid bodies in this binding.

Mirrors PhysX SDK PxRigidDynamic::wakeUp. Bodies that still have RIGID_BODY_DISABLE_SIMULATION set are silently skipped (the engine refuses to wake disabled actors).

Typical pair: clear the disable flag on an actor (re-add it to simulation in a sleep state) and then call this so the actor is active for the next step().

Only valid on a rigid-body binding. Articulation bindings raise.

Parameters:

indices – Optional int32 DLPack-compatible tensor of indices into this binding. If None, every body in the binding is woken.

Errors:

RuntimeError if the binding is destroyed, is not a rigid-body binding, has been invalidated by a stage change, or the engine wake call fails.

write(tensor, indices=None, mask=None) → None#

Write data from a user-provided tensor into the simulation (synchronous).

The tensor must have matching shape and dtype (shape and dtype). Can be a NumPy array, PyTorch tensor, or any object with __dlpack__ protocol.

When called repeatedly with the same supported buffer object and no indices/mask, an internal cache reuses descriptor metadata and attribute lookups. Producer readiness is checked on every call. Callers that want this fast path should reuse the same tensor object with unchanged backing storage across calls. See read() for the supported providers and full contract.

Parameters:
  • tensor – DLPack-compatible tensor with data to write, shape matching self.shape. Must use self.dtype. When CUDA is available, CPU/CUDA device mismatches are staged for binding types whose storage follows the simulation device. For CPU-only property bindings, this tensor and optional indices or mask must be host-resident (kDLCPU or kDLCUDAHost), including on GPU simulations; CUDA and CUDA-managed tensors are rejected rather than staged. Cross-GPU mismatches and CUDA tensors in process-wide CPU-only mode are rejected.

  • indices – Optional int32 tensor of indices for partial update. If provided, only the rows at the given indices are written. The tensor argument must still be full shape [N, …] matching the binding spec; only the selected rows are applied. Shape of indices: [K] where K <= N.

  • mask –

    Optional bool/uint8 tensor for masked update. If provided, only elements where mask[i] != 0 are written. Shape: [N] matching the binding’s first dimension. When mask is provided, tensor must be full shape [N, …]. If both mask and indices are provided, mask takes precedence and indices are ignored (with a warning).

    Note: there is no corresponding read(..., mask=...). Reads always return the full [N,…] tensor and callers can index the result themselves. This write-only mask design matches other RL physics APIs such as Newton’s selectionAPI, where masks selectively apply actions but observations are always returned in full.

Preconditions:
  • This binding is not destroyed.

  • tensor matches shape and dtype and uses a supported device.

  • indices (if provided) is int32 and within bounds.

  • mask (if provided) is bool/uint8 with shape [N] on a supported device.

Side effects:
  • Updates simulation state for the bound entities.

Ownership/Lifetime:
  • Caller owns tensor/indices/mask storage and must keep it alive for the call.

Threading:
  • Serialized per binding via an internal lock.

Errors:
  • RuntimeError if write fails (shape mismatch, device mismatch, etc.).

class ovphysx.api.ContactBinding(
sdk,
handle: int,
sensor_count: int,
filter_count: int,
max_contact_data_count: int,
)#

Bases: object

Contact tensor binding backed by IRigidContactView.

Deprecated since version 0.6.0: The contact-binding API is deprecated and retained for compatibility.

Do not instantiate directly. Use PhysX.create_contact_binding() to obtain an instance. The sensor_paths and filter_paths properties expose the row/column metadata for the returned tensors.

destroy() → None#

Release contact binding resources.

Safe to call multiple times. Captures strong references to the SDK and library before the C call to guard against GC ordering issues (Python may collect self._sdk before self if both go out of scope together).

property filter_count: int#

Number of filter bodies per sensor (0 when no filters specified).

property filter_paths: list[list[str]]#

Resolved filter physics-object paths in contact tensor column order.

The outer list is indexed by sensor row and the inner list by filter column. Each inner list is empty for unfiltered contact bindings (i.e. when filter_count == 0).

Returns:

Nested list of shape [sensor_count][filter_count].

Return type:

list[list[str]]

get_other_actor_paths_from_ids(ids_array) → list[str]#

Resolve actor IDs from read_raw_contact_data() to physics-object paths.

ids_array is a 1D int64/uint64 array (numpy / warp / torch with DLPack support) holding actor IDs, from either column of the actor_ids tensor. Both use the same namespace. A column is a strided view and this boundary requires C-contiguous input, so wrap a column slice in np.ascontiguousarray() before passing it. Path strings are copied into Python, so the caller can keep them across subsequent ovphysx calls.

Every non-zero ID is checked against the attached stage first, so an ID whose actor has been removed yields an empty path rather than the path it used to name. Since the caller holds the IDs, that makes the failure explicit: a non-zero ID with an empty path is stale, while ID 0 simply means no actor. The check is as precise as the backend’s notion of existence. On a USD stage a merely deactivated prim still resolves.

Returns:

Physics-object paths in the same order as the input IDs.

Return type:

list[str]

property max_contact_data_count: int#

Flat-buffer capacity for detailed contact and friction reads.

read_contact_data(
contact_forces,
positions,
normals,
separations,
counts,
start_indices,
) → int#

Deprecated alias of read_normal_contact_data(); forces contain only normal components.

read_force_matrix(output) → None#

Deprecated alias of read_normal_force_matrix(); returns normal forces only.

read_friction_contact_data(
friction_forces,
friction_points,
counts,
start_indices,
) → int#

Read detailed friction contact data into flat buffers.

Deprecated since version 0.6.0: The contact-binding API is deprecated and retained for compatibility.

Returns world-space friction force vectors at friction anchors. These anchors need not correspond one-to-one with the contact points from read_normal_contact_data(); use this read’s own counts and start indices.

Expected shapes are [C, 3] for friction_forces and friction_points, and [sensor_count, filter_count] for counts and start_indices. C is max_contact_data_count and must be positive, and filter_count must also be positive. Count and start-index tensors may be int32 or uint32. Friction entries are per-anchor. Sum each flat slice to build a pair-level [sensor_count, filter_count, 3] force tensor. Friction forces use the timestep from the last successful PhysX.step() or PhysX.step_sync() call that simulated; a zero-dt step is skipped and changes neither the contacts nor the timestep.

Returns the total number of friction anchors produced for the step. When this exceeds max_contact_data_count, the buffers contain the valid prefix that fit. A pair’s count reports only anchors actually written, and its start index is clamped to max_contact_data_count, so [start, start + count) is always an in-range (possibly empty) slice. Recreate the binding with at least the returned capacity, step again, and retry to obtain a complete result.

read_friction_data(
friction_forces,
friction_points,
counts,
start_indices,
) → int#

Deprecated alias of read_friction_contact_data().

read_friction_force_matrix(output) → None#

Read friction forces into output, shape [sensor_count, filter_count, 3].

Deprecated since version 0.6.0: The contact-binding API is deprecated and retained for compatibility.

Each entry sums world-space friction forces for its sensor/filter pair, independently of detailed-contact capacity. Only contacts with configured filter bodies contribute. Adding read_normal_force_matrix() from the same step yields total contact forces for those pairs. Individual friction forces and anchor points are available through read_friction_contact_data().

Impulse-to-force conversion uses the dt of the last step that actually simulated; a zero-dt step is skipped and changes neither the contacts nor the dt.

read_net_forces(output) → None#

Deprecated alias of read_net_normal_forces(); returns normal forces only.

read_net_friction_forces(output) → None#

Read net friction forces into output, shape [sensor_count, 3].

Deprecated since version 0.6.0: The contact-binding API is deprecated and retained for compatibility.

Sums world-space friction-anchor forces over all reported contacts of each sensor, including contacts with bodies not matched by the configured filters. Filters and detailed-contact capacity are not required. Adding the result to read_net_normal_forces() from the same step yields the total contact force. Impulse-to-force conversion uses that step’s dt.

For example, if a foot touches the floor and a wall but its filter selects only the floor, this function includes friction from both bodies. The friction force matrix includes only the floor contribution.

Opposing anchor forces may cancel while producing torque. This vector sum does not report friction torque.

read_net_normal_forces(output) → None#

Read net normal forces into output, shape [sensor_count, 3].

Deprecated since version 0.6.0: The contact-binding API is deprecated and retained for compatibility.

Sums world-space normal forces over all reported contacts of each sensor, regardless of filters or detailed-contact capacity. Add read_net_friction_forces() from the same step for total contact force. Impulse-to-force conversion uses the dt of the last step that actually simulated; a zero-dt step is skipped and changes neither the contacts nor the dt.

read_normal_contact_data(
contact_forces,
positions,
normals,
separations,
counts,
start_indices,
) → int#

Read detailed normal contact data into flat buffers.

Deprecated since version 0.6.0: The contact-binding API is deprecated and retained for compatibility.

contact_forces contains scalar normal forces. Multiply each scalar by the corresponding normals vector to obtain the world-space normal force vector. Friction forces are returned separately by read_friction_contact_data().

Expected shapes are [C, 1] for contact_forces and separations, [C, 3] for positions and normals, and [sensor_count, filter_count] for counts and start_indices. C is max_contact_data_count. Both C and filter_count must be positive. Count and start-index tensors may be int32 or uint32. Contact force magnitudes use the timestep from the last successful PhysX.step() or PhysX.step_sync() call that simulated; a zero-dt step is skipped and changes neither the contacts nor the timestep.

Returns the total number of contacts produced for the step. When this exceeds max_contact_data_count, the buffers contain the valid prefix that fit. A pair’s count reports only contacts actually written, and its start index is clamped to max_contact_data_count, so [start, start + count) is always an in-range (possibly empty) slice. Recreate the binding with at least the returned capacity, step again, and retry to obtain a complete result.

read_normal_force_matrix(output) → None#

Read normal forces into output, shape [sensor_count, filter_count, 3].

Deprecated since version 0.6.0: The contact-binding API is deprecated and retained for compatibility.

Each entry sums world-space normal forces for its sensor/filter pair, independently of detailed-contact capacity. Adding read_friction_force_matrix() from the same step yields total contact forces for the configured pairs. Impulse-to-force conversion uses the dt of the last step that actually simulated; a zero-dt step is skipped and changes neither the contacts nor the dt.

read_raw_contact_data(
contact_forces,
positions,
normals,
separations,
sensor_layout,
actor_ids,
) → int#

Read raw (unfiltered) contact data into flat buffers.

Filter-less variant of read_normal_contact_data(). Returns every contact involving each sensor regardless of which other actor it collided with, plus per-contact actor-identity tensors for identifying both the sensor and the contacting body via get_other_actor_paths_from_ids().

Expected shapes are [C, 1] for contact_forces and separations, [C, 3] for positions and normals, [sensor_count, 2] for sensor_layout (column 0 count, column 1 start index), and [C, 2] for actor_ids (column 0 the reporting sensor’s actor, column 1 the actor it contacted). C is max_contact_data_count and must be positive. No filter dimension is required. sensor_layout may be int32 or uint32. actor_ids must be int64 or uint64. Slicing the columns out as views costs no copy. Contact force magnitudes use the timestep from the last successful PhysX.step() or PhysX.step_sync() call that simulated; a zero-dt step is skipped and changes neither the contacts nor the timestep.

Returns the total number of contacts produced for the step. When this exceeds max_contact_data_count, the buffers contain the valid prefix that fit. A sensor’s count reports only contacts actually written, and its start index is clamped to max_contact_data_count, so [start, start + count) is always an in-range (possibly empty) slice. Recreate the binding with at least the returned capacity, step again, and retry to obtain a complete result.

Token lifetime: tokens in actor_ids are opaque actor handles, not encoded paths, and are stable while the corresponding actor is alive on the attached stage. After an actor is removed, its token is stale and get_other_actor_paths_from_ids() reports it as an empty path rather than as the path it used to name.

property sensor_count: int#

Number of sensor bodies matched.

property sensor_paths: list[str]#

Resolved sensor physics-object paths in contact tensor row order.

Returns:

One path per sensor row, in the same order as the contact data tensors.

Return type:

list[str]

Task Completion#

PhysX.step(), PhysX.clone(), PhysX.attach_ovstage(), PhysX.update_from_ovstage() and PhysX.detach_ovstage() return an immutable Task receipt. Collect one task’s outcome with ovphysx.api.PhysX.wait_task() or every uncollected task with ovphysx.api.PhysX.wait_all(); both return None on success and raise the exceptions below on failure or timeout.

Stage lifecycle tasks currently execute inline, but a returned receipt reports admission only. Keep the Stage alive until successful detach or instance destruction, and wait before consuming the result of attach or update. PhysX.is_stage_attached() is a synchronous ownership snapshot, not a completion or readiness check. PhysX.reset_stage() has been removed; use PhysX.detach_ovstage() for teardown. Neither operation restores initial poses.

The session API (query(), read(), write(), fetch_next(), commit() and close()) returns an Operation without waiting. Operation.wait() collects its native tasks and returns the typed result; Operation.result never waits. wait_all() also collects outstanding operations and caches their outcomes. read_sync(), read_tokens_sync(), write_sync(), commit_sync(), close_sync(), update_articulations_kinematic() and evaluate_sdf_shapes() wait for their native tasks internally. Waiting raises TaskError for accepted execution failures. ctypes exposes the complete native receipts. CUDA producer-event and consumer-stream dependencies remain necessary; a completed host task does not imply all GPU work is finished.

Run custom application code directly after the relevant task wait succeeds. wait_task(task) collects only that task; wait_all() also collects and acknowledges earlier uncollected outcomes, including failures.

class ovphysx.api.Task(status: ApiStatus, op_index: int, instance: int)#

Bases: object

Immutable receipt for an accepted operation, without instance ownership.

Pass the receipt to PhysX.wait_task on its owning instance. Completion is collected once, either by that wait or by PhysX.wait_all. Discarding a receipt does not discard an uncollected failure. status describes admission, op_index identifies the task within its instance, and instance is the owning native handle without a lifetime reference.

exception ovphysx.api.TaskError(errors: tuple[tuple[Task, str], ...])#

Bases: RuntimeError

Collected task failures, copied independently of native result storage.

property errors: tuple[tuple[Task, str], ...]#

Immutable (Task, message) entries in collection order.

exception ovphysx.api.TaskTimeoutError(
errors: tuple[tuple[Task, str], ...],
pending_task: Task,
)#

Bases: TimeoutError

A wait deadline expired, possibly after collecting earlier failures.

property errors: tuple[tuple[Task, str], ...]#

Immutable completed failures collected before the pending task.

property pending_task: Task#

Earliest unfinished task, which remains available for another wait.

Session Read/Write#

ovphysx.api.PhysX.query(), ovphysx.api.PhysX.read() and ovphysx.api.PhysX.write() return operations whose results are the types below. The Overview pages describe the data contract.

class ovphysx.api.Operation(
sdk,
tasks=(),
*,
convert=lambda : ...,
cleanup=None,
keepalive=(),
on_complete=None,
owners=(),
)#

A typed result of zero, one, or several real native tasks.

wait() collects completion explicitly. result never waits and raises while an outcome is uncollected. Outcomes are cached after either operation waits or the owning PhysX instance’s waits. Payload conversion runs once on first result access, on the submitting thread. In particular, read arrays use the Warp stream current at that access, not the stream used by wait_all.

Inputs and output slots survive until collection, even if the operation is dropped. Periodically call wait_all() for fire-and-forget submissions. Collecting Python-owned receipts directly through the C API is unsupported.

property done: bool#

Whether every native outcome has been collected; does not poll.

property result: T#

Return the cached typed result without waiting.

property task#

The native receipt, available only for a single-task operation.

property tasks#

Immutable tuple of the operation’s real native receipts.

wait(
*,
timeout_ns: int | None = None,
) → T#

Collect this operation’s tasks and return its typed result.

A finite timeout is one readiness budget across all constituent tasks. Completed failures are cached, including when a later task times out.

class ovphysx.api.Query(sdk, handle, object_type, metadata, stage, attachment)#

A completed reusable selector owned by one instance and attachment.

Release independently of sessions already opened from it. Whole-type queries evaluate membership at each session open; selected queries keep their resolved membership. Recreate a query to refresh its creation-time discovery metadata.

property dictionary#

Owner-aware PathDictionary for tokens and prim lists of this query.

class ovphysx.api.ReadResult(
sdk,
query: int,
read: int,
groups=None,
group_ids=(),
release=None,
*,
metadata=None,
object_type=SimObjectType.RIGID_BODY,
stage=None,
attachment=None,
)#

A completed read session with explicit asynchronous group fetches.

fetch_next().wait() exposes one group, or None at successful EOF. Opening a session does not fetch its groups. Numeric Warp aliases keep snapshot storage alive after logical close; dictionary metadata does not survive group release or attachment invalidation. The caller’s Query is independent.

close() → Operation[None]#

Logically close and submit group releases, without waiting for aliases.

The owner reference drops once every group release is admitted. Rejected admission retains it for retry. Pending fetches and returned arrays keep the physical snapshot alive until their own references are retired.

property dictionary#

Owner-aware dictionary; never resolves through a retired query.

fetch_next() → Operation[ReadGroup | None]#

Submit one fetch; materialize its arrays only on typed result access.

release() → Operation[None]#

Logically close and submit group releases, without waiting for aliases.

The owner reference drops once every group release is admitted. Rejected admission retains it for retry. Pending fetches and returned arrays keep the physical snapshot alive until their own references are retired.

class ovphysx.api.ReadGroup(
attribute: int,
object_type: SimObjectType,
ordinal: int,
is_array: bool,
is_delete: bool,
semantic: int,
prim_list: int,
prim_offset: int,
prim_count: int,
prim_index_map: object,
index_map: object,
layout_generation: int,
write_floor_ordinal: int,
tensors: list,
cuda_stream: int = 0,
cuda_wait_event: int = 0,
)#

One physics-output column group returned by ReadResult.fetch_next().

A flattened view of the native ovstage_read_group_t the read returns (its prims / data / meta sub-structs unpacked into these fields). The interned identifiers (attribute token and prim_list handle) resolve through the owning attached Stage path dictionary, so an ovstage.PathDictionary(stage) resolves them, and prim_list feeds straight into stage.query_from_path_list for a no-repack write-back. object_type is NOT part of the native group (the read is opened over one type). It is stamped here from the object_type of the session’s Query.

Constant on the physics-output path (so callers can rely on them): is_delete is always False (this read never emits tombstones). prim_offset is 0 and prim_index_map is None (each group carries its own full prim_list). ordinal is 0 (groups are not ordinal-stamped here).

attribute#

Interned EMITTED attribute token (resolve via the path dictionary). May differ from the requested name: a “position” request on a point-instancer is emitted as “positions” (instancer-local). Write back using this token, not the requested string.

Type:

int

object_type#

The queried SimObjectType (stamped from the query, not carried by the native ovstage group).

Type:

ovphysx.types.SimObjectType

ordinal#

The data ordinal of this group (0 on this path).

Type:

int

is_array#

Follows the SOURCE attribute kind: True for a ragged / USD-array / byte-string column (e.g. a point-instancer’s positions, a deformable mesh’s points), False for a fixed scalar column. It is NOT decided by whether the per-element dims happen to be uniform: a fixed-width array attribute is still is_array=True. It is the only signal that tells e.g. a 1-byte string from a scalar uint8 apart.

Type:

bool

is_delete#

Always False for physics output (tombstone flag).

Type:

bool

semantic#

Authored USD interpretation (ovstage_attribute_semantic_t value).

Type:

int

prim_list#

Interned prim-path-list handle covering this group’s prims.

Type:

int

prim_offset#

Start index within prim_list (0 on this path).

Type:

int

prim_count#

Number of prims in this group.

Type:

int

prim_index_map#

CPU warp.array of uint32 sparse indices into prim_list, or None for a contiguous range (always None on this path).

Type:

object

index_map#

CPU warp.array of uint32 values (gather/scatter over the OUTER element axis), or None. None for point-instancer rigid-body output, which always emits the instancer’s full instance array (by-index) so it forwards into the ovstage write path verbatim. Slots without a live body are zero-filled in every array; an all-zero orientations quaternion is the absent-slot marker because live orientations are normalized and never all zero.

Type:

object

layout_generation#

Reserved metadata field. The current output producer always returns 0. Do not use it for structural invalidation.

Type:

int

write_floor_ordinal#

Reserved metadata field. The current output producer always returns 0. The application owns ovstage write-floor advancement.

Type:

int

tensors#

One warp.array per native tensor (1 for a fixed column; per-prim for an array group). A tuple width above 1 is the trailing dim (a vec3 column is shape [N, 3]); a single-lane column stays [N]. Non-empty arrays alias the read session’s snapshot storage and keep it alive, so CPU and CUDA arrays are both safe to keep after the ReadResult closes.

Type:

list

cuda_stream#

Producer stream for a device column, or 0. The read emits 0: it does not ask a consumer to drain a stream, which is what a non-zero value means to ovstage.

Type:

int

cuda_wait_event#

CUDA event (as an integer handle) that a device column’s producer work signals, or 0 for a host column. A device column is handed over before its work has necessarily completed. The read does not block on the consumer’s behalf.

The Python binding enqueues a wait on this event for the Warp stream current during the first fetch-operation result access. It does not block the host, and no other stream is ordered, so the caller must establish its own Warp stream dependency before using the array elsewhere. The handle stays valid until the read session is released. Do not destroy it.

Type:

int

class ovphysx.api.WriteSession(
sdk,
query: int,
write: int,
groups=None,
native=None,
*,
metadata=None,
attributes=(),
stage=None,
attachment=None,
object_type=None,
)#

A completed write session; fetch, commit and close return uncollected operations.

Fill fetched groups in place and commit each explicitly. A successful earlier commit remains applied when a later commit fails; an accepted failed commit may have partially applied rows and must never be retried. Caller commit order determines command/property ordering. The caller’s Query is not owned here. Group arrays are borrowed: do not access them after commit admission or close.

close() → Operation[None]#

Submit release. Rejected admission leaves ownership available for retry.

Finish CUDA fills of uncommitted groups first; close takes no producer synchronization handles.

commit(
group: WriteGroup,
cuda_stream: int = 0,
cuda_wait_event: int = 0,
*,
event_owner=None,
) → Operation[None]#

Submit a filled group’s publication, spending it on admission.

Complete host fills before calling. For outstanding CUDA fills, pass the producer stream, completion event, or both; both dependencies are honored when supplied. They do not select PhysX’s execution stream. Only two zero handles assert that no producer work remains, even for host-resident data. Stream 1 names the legacy default stream in the caller’s current CUDA context; make the producer context current when using this sentinel.

Keep supplied streams and events valid through commit completion. Pass event_owner to retain their Python owner, or a tuple of owners, through collection. The current native implementation may block this call while completing producer dependencies. A successful task confirms CPU mutation or GPU submission; GPU execution can continue afterward. Synchronization errors fail the task and the admitted group remains spent.

fetch_next() → Operation[WriteGroup | None]#

Submit one fetch. A successful result of None is end of iteration.

release() → Operation[None]#

Submit release. Rejected admission leaves ownership available for retry.

Finish CUDA fills of uncommitted groups first; close takes no producer synchronization handles.

class ovphysx.api.WriteGroup(
prim_list: int,
prim_offset: int,
prim_count: int,
tensors: list,
attribute_index: int,
attribute: int,
)#

Writable zero-copy buffers for one original attribute request.

attribute_index identifies the original request; attribute is its canonical token. Use the exact group with its session’s commit operation. Accepted commit, session release, or attachment teardown ends buffer access, including when a commit subsequently fails. Commits are not transactional.

attribute: int#

Alias for field number 5

attribute_index: int#

Alias for field number 4

prim_count: int#

Alias for field number 2

prim_list: int#

Alias for field number 0

prim_offset: int#

Alias for field number 1

tensors: list#

Alias for field number 3

class ovphysx.api.QueryMetadata(total_prim_count: int, attributes: tuple[int, ...])#

Creation-time discovery; attributes and counts are immutable snapshots.

class ovphysx.api.ReadMetadata(
total_prim_count: int,
attributes: tuple[ovphysx.api.ReadAttributeResult, ...],
)#
class ovphysx.api.ReadAttributeResult(
attribute: int,
group_count: int,
omission_reasons: ovphysx.api.ReadOmission,
)#
class ovphysx.api.ReadOmission(
value,
names=_not_given,
*values,
module=None,
qualname=None,
type=None,
start=1,
boundary=None,
)#

Reasons applicable selected partitions did not produce a requested column.

class ovphysx.api.WriteMetadata(
total_prim_count: int,
attributes: tuple[ovphysx.api.WriteAttributeResult, ...],
)#
class ovphysx.api.WriteAttributeResult(attribute: int, group_count: int)#

Schema Providers#

Applications install physx-usd-schemas independently and register its two resource directories before population. See Physics Schemas for metadata-based discovery and native deployment recipes.

The Newton USD schema (pip install newton-usd-schemas) is a separate package whose newton:* attributes ovphysx reads as fallbacks for the PhysX spellings; this helper locates the installed package so it can be registered in the same call.

ovphysx.newton_schema_root() → Path#

Return the directory of the installed Newton USD schema (newton-usd-schemas).

Register it with ovstage alongside the external PhysX schemas, before the first population call in the process; the parser reads the schema’s newton:* attributes as fallbacks for the PhysX spellings, and population drops them unless the schema is registered.

Raises:

FileNotFoundError – If the newton-usd-schemas package is not installed in this Python environment. The message carries the install hint.

Logging#

ovphysx.api.set_log_level(level: int) → None#

Set the process-scoped libovphysx source log level threshold.

Messages emitted under the named Carbonite sources omni_physx_sdk, omni.physx, and ovphysx_internal below this level are suppressed for console and callback delivery. Every other process source and channel, including any unnamed source, remains unchanged and is subject only to the callback’s severity and channel filter. Callable at any time, including before instance creation. LogLevel.NONE mutes only the three named sources. It is not a whole-runtime or process mute.

Parameters:

level – Log level threshold (LogLevel.DEFAULT through LogLevel.NONE). LogLevel.DEFAULT restores LogLevel.WARNING.

Raises:
  • ValueError – If level is out of range. No state change is applied.

  • RuntimeError – If the native API rejects the call for another reason, including callback-time reconfiguration.

ovphysx.api.get_log_level() → int#

Get the current process-scoped libovphysx source log level threshold.

Returns:

The current log level (int matching ovphysx_log_level_t constants).

ovphysx.api.enable_default_log_output(enable: bool = True) → None#

Enable or disable Carbonite’s built-in console log output.

By default, Carbonite logs to the console. When a custom callback is set (or enable_python_logging() is active), both the built-in console output and the callback receive messages, which may cause duplicate output.

Call with False to suppress the built-in console output while keeping the callback active. Call with True to re-enable it.

This is independent of callback registration and the libovphysx source log level. It controls Carbonite’s process-global built-in console logger and therefore affects every Carbonite tenant in the process. Multi-tenant hosts should normally own this policy and leave the logger enabled.

Parameters:

enable – True to enable (default), False to disable.

Raises:

RuntimeError – If the native API rejects the call, including when it is made from the active native log callback.

ovphysx.api.flush_log(timeout_ns: int = 1 << 64 - 1) → None#

Wait for callback delivery already accepted before this call.

The barrier covers records already handed to ovphysx by Carbonite. If the host enabled Carbonite asynchronous logging, records still buffered upstream are outside this barrier. Successful native shutdown flushes the upstream buffer before disabling and draining the callback.

Parameters:

timeout_ns – Maximum wait in nanoseconds. Zero polls; 2**64 - 1 waits indefinitely.

Raises:
  • ValueError – If timeout_ns is outside the unsigned 64-bit range.

  • TimeoutError – If the timeout expires.

  • RuntimeError – If native log delivery cannot be flushed.

ovphysx.api.enable_python_logging(
logger_name: str = 'ovphysx',
*,
min_severity: int = LogLevel.VERBOSE,
channel_filter: str | None = None,
) → None#

Route native log messages to Python’s logging module.

Sets the sole C-level callback slot and forwards matching native messages to logging.getLogger(logger_name). Calling this function again replaces any existing native callback, including one installed outside Python. Successful shutdown of the Python process-lifecycle scope, normally when the final PhysX instance is destroyed, also disables this bridge. Enable it again after creating an instance in a new lifecycle scope. Each forwarded LogRecord includes ovphysx_channel and ovphysx_timestamp attributes for the native source and Unix-epoch timestamp seconds.

Call disable_python_logging() to stop forwarding.

Parameters:
  • logger_name – Name of the Python logger to route to (default: “ovphysx”).

  • min_severity – Minimum severity for records observed from the process log stream (default: LogLevel.VERBOSE). Records from libovphysx’s omni_physx_sdk, omni.physx, and ovphysx_internal sources are also subject to set_log_level().

  • channel_filter – Optional comma-separated channel=level rules. The native API copies this string, compares levels case-insensitively, and uses raw channel-prefix matching. The longest matching prefix wins. A later rule wins ties of equal length.

Raises:

RuntimeError – If called from a native log callback, another Python logging transition is in progress, or the native API rejects the severity, filter, or callback configuration.

ovphysx.api.disable_python_logging() → None#

Stop routing native log messages to Python’s logging module.

If enable_python_logging() was not called, this is a no-op.

Raises:

RuntimeError – If called from a native log callback or while another Python logging transition is in progress.

Configuration#

Process-global keys use ovphysx.api.set_global_config() / ovphysx.api.get_global_config(); startup-only keys must be set before the first PhysX(). Configure every setting with a GlobalConfigKey through set_global_config, and create the instance with no config args for those settings. Set ovphysx.types.ConfigKey.ACTIVE_CUDA_GPUS with ovphysx.api.PhysX.set_config() after create and before attach. Environment variables remain authoritative over the matching global setter.

PhysXConfig, config= on PhysX(), and the typed ConfigBool / ConfigInt32 / ConfigString enums are the legacy path. Carbonite-only settings, such as DirectGPU and tasking/TBB pool sizes, still use PhysXConfig.carbonite_overrides. Passing config= emits a DeprecationWarning for this legacy path.

ovphysx.api.set_global_config(
key: GlobalConfigKey,
value: bool | int | float | str,
) → None#

Set one process-global value. Environment overrides remain authoritative.

ovphysx.api.get_global_config(
key: GlobalConfigKey,
) → bool | int | float | str | None#

Return one effective process-global value.

Unset strings return None. Scalar keys return their declared default when nothing has been set.

Typed config for ovphysx.

@implements REQ-CAPI-PROFILER-001 @covers AC-6

Provides PhysXConfig, a dataclass whose fields map 1:1 to the C typed config enums in ovphysx_types.h. Only non-None fields are applied. The rest keep their Carbonite/PhysX defaults.

Usage:

from ovphysx import PhysX, set_global_config
from ovphysx.types import GlobalConfigKey

set_global_config(GlobalConfigKey.DISABLE_CONTACT_PROCESSING, True)
set_global_config(GlobalConfigKey.NUM_THREADS, 4)
physx = PhysX()

PhysXConfig is the legacy path. Carbonite-only settings still use carbonite_overrides; passing config= emits a DeprecationWarning.

class ovphysx.config.OmniPvdDestination(
transport: str,
file_path: str = '',
tcp_address: str = '',
tcp_port: int = 0,
tcp_timeout_ms: int = 0,
)#

Bases: object

Exact destination for an explicit OVD recording session.

classmethod file(
path: str,
) → OmniPvdDestination#

Record to the exact file path path.

file_path: str = ''#
classmethod tcp(
address: str,
port: int,
*,
timeout_ms: int = 0,
) → OmniPvdDestination#

Connect to a ready TCP listener.

tcp_address: str = ''#
tcp_port: int = 0#
tcp_timeout_ms: int = 0#
transport: str#
class ovphysx.config.PhysXConfig(
disable_contact_processing: bool | None = None,
collision_cone_custom_geometry: bool | None = None,
collision_cylinder_custom_geometry: bool | None = None,
num_threads: int | None = None,
scene_multi_gpu_mode: int | None = None,
profiler_backend: str | int | None = None,
profiler_output_path: str | None = None,
cooked_collider_cache_dir: str | None = None,
ovstage_read_pool_max_mb: int | None = None,
carbonite_overrides: dict[str, bool | int | float | str] | None = None,
)#

Bases: object

Typed configuration for ovphysx.

All fields default to None (= use Carbonite/PhysX default). Only non-None fields are applied.

Settings with a GlobalConfigKey use the global API instead:

from ovphysx import PhysX, set_global_config
from ovphysx.types import GlobalConfigKey

set_global_config(GlobalConfigKey.DISABLE_CONTACT_PROCESSING, True)
set_global_config(GlobalConfigKey.NUM_THREADS, 4)
physx = PhysX()

Carbonite-only settings still use carbonite_overrides; passing config= emits a DeprecationWarning.

carbonite_overrides: dict[str, bool | int | float | str] | None = None#
collision_cone_custom_geometry: bool | None = None#
collision_cylinder_custom_geometry: bool | None = None#
cooked_collider_cache_dir: str | None = None#

Directory for the local cooked-collider (UJITSO) cache. Provide this to persist cooked colliders across runs and reuse them on the next launch. If left None, ovphysx cooks to a process-private temp directory that is discarded at shutdown, so nothing persists. Applied when the runtime first starts in a process. Later changes have no effect.

disable_contact_processing: bool | None = None#
num_threads: int | None = None#
ovstage_read_pool_max_mb: int | None = None#

Retention budget in MiB for the per-context device read-buffer pool that backs the ovstage output read (/physics/ovstageReadPoolMaxMB). Bounds the device and pinned-host memory the pool keeps between reads for reuse. 0 or any negative value DISABLES the pool (nothing is retained and every read allocates and frees as if the pool were absent). Default 256 when left None. Does not cap the memory a single read allocates, only what is retained.

profiler_backend: str | int | None = None#

Profiler backend for the ovphysx API zones, the runtime’s host-side zones (stage load, collision cooking, step orchestration) and the PhysX SDK profile zones. Accepts "none", "nvtx" or "trace" (case-insensitive), or a PROFILER_BACKEND_* value. Off by default; must be set before instance creation, because the profiler is bound during engine startup. Setting OVPHYSX_PROFILER=nvtx in the environment has the same effect.

profiler_output_path: str | None = None#

Destination file for profiler_backend="trace", ignored by the other backends. Unset writes ct-profile <date> <time>.json to the working directory. The trace is written when the last instance shuts down. Setting OVPHYSX_PROFILER_OUTPUT in the environment has the same effect.

scene_multi_gpu_mode: int | None = None#

0=disabled, 1=all GPUs, 2=skip first GPU. Used only when active_cuda_gpus is empty

OVD recording#

Set recording capability with set_global_config(GlobalConfigKey.OVD_RECORDING_CAPABLE, True) before the first PhysX(), attach a scene, then use start_recording() with an explicit FILE or TCP destination. Start before the first simulation step to capture it. Creation and attachment leave output dormant. Startup config fields, including PhysXConfig.omnipvd_recording_capable, and the legacy OVD config module are removed. See Instance and OVD API migration.

Types and Enums#

Pure-Python type definitions for ovphysx.

@implements REQ-CAPI-PROFILER-001 @covers AC-2

This module contains IntEnum definitions that mirror the C enums in ovphysx/include/ovphysx/ovphysx_types.h and the legacy-only enums in ovphysx/include/ovphysx/ovphysx_legacy_types.h. It has zero native dependencies (no ctypes, no shared library loading, no USD) and is safe to import in any Python process regardless of USD version or native library state.

Keeping this module dependency-free is intentional: downstream consumers like IsaacLab can import TensorType without triggering ovphysx’s native bootstrap or USD version checks.

Naming convention: strip the OVPHYSX_TENSOR_ prefix and scalar dtype suffix (_F32 or _S32) from the C enum name. This keeps names unambiguous (ARTICULATION_ vs RIGID_BODY_) and makes the _bindings.py aliases mechanically verifiable.

class ovphysx.types.ApiStatus(
value,
names=_not_given,
*values,
module=None,
qualname=None,
type=None,
start=1,
boundary=None,
)#

Bases: IntEnum

Return codes from the ovphysx C API. Mirrors ovphysx_api_status_t.

BUFFER_TOO_SMALL = 6#
DEVICE_MISMATCH = 7#
ERROR = 1#
GPU_NOT_AVAILABLE = 8#
INVALID_ARGUMENT = 4#
INVALID_STATE = 9#
NOT_FOUND = 5#
NOT_IMPLEMENTED = 3#
SUCCESS = 0#
TIMEOUT = 2#
class ovphysx.types.ArticulationKinematicFlag(
value,
names=_not_given,
*values,
module=None,
qualname=None,
type=None,
start=1,
boundary=None,
)#

Bases: IntFlag

Articulation state propagated by update_articulations_kinematic.

POSITION = 1#
VELOCITY = 2#
class ovphysx.types.BindingPrimMode(
value,
names=_not_given,
*values,
module=None,
qualname=None,
type=None,
start=1,
boundary=None,
)#

Bases: IntEnum

Prim selection mode for tensor bindings.

Deprecated since version 0.6.0: The tensor-binding API is deprecated. Use PhysX.read() for reads and PhysX.write() for writes.

Unlike the other enums in this module, BindingPrimMode does not have a named typedef in ovphysx_types.h. The values come from the internal implementation. It is not covered by test_types_sync.py.

CREATE_NEW = 2#
EXISTING_ONLY = 0#
MUST_EXIST = 1#
class ovphysx.types.ConfigBool(
value,
names=_not_given,
*values,
module=None,
qualname=None,
type=None,
start=1,
boundary=None,
)#

Bases: IntEnum

Deprecated boolean configuration keys.

COLLISION_CONE_CUSTOM_GEOMETRY = 1#
COLLISION_CYLINDER_CUSTOM_GEOMETRY = 2#
DISABLE_CONTACT_PROCESSING = 0#
class ovphysx.types.ConfigFloat(
value,
names=_not_given,
*values,
module=None,
qualname=None,
type=None,
start=1,
boundary=None,
)#

Bases: IntEnum

Deprecated float configuration keys.

class ovphysx.types.ConfigInt32(
value,
names=_not_given,
*values,
module=None,
qualname=None,
type=None,
start=1,
boundary=None,
)#

Bases: IntEnum

Deprecated int32 configuration keys.

NUM_THREADS = 0#
OVSTAGE_READ_POOL_MAX_MB = 4#
PROFILER_BACKEND = 5#
SCENE_MULTI_GPU_MODE = 1#
class ovphysx.types.ConfigKey(
value,
names=_not_given,
*values,
module=None,
qualname=None,
type=None,
start=1,
boundary=None,
)#

Bases: IntEnum

Per-instance configuration keys.

ACTIVE_CUDA_GPUS = 65536#
class ovphysx.types.ConfigString(
value,
names=_not_given,
*values,
module=None,
qualname=None,
type=None,
start=1,
boundary=None,
)#

Bases: IntEnum

Deprecated string configuration keys.

COOKED_COLLIDER_CACHE_DIRECTORY = 1#
PROFILER_OUTPUT_PATH = 4#
class ovphysx.types.ContactSelection(
sensors: str | Sequence[int],
filters: Sequence[str | Sequence[int]] = (),
)#

Bases: NamedTuple

One contact-sensor selection and its filters, for PhysX.query(..., contacts=[...]) (ADR-0044).

sensors selects sensor bodies – and, on CPU simulation or GPU dynamics with CPU readback, colliders carrying PhysxContactReportAPI (host-only; a DirectGPU scene has no separate child-collider rows, and a body row overlaps its collider rows, so don’t sum across them). Each entry of filters must match one object, shared by every sensor of this selection, or exactly one object per sensor, paired by position. Every selection is either a glob str or a list of native ovx_primpath_t handles, as for pattern and prim_paths. All selections of one query carry the same number of filters.

A separate child collider’s schema enables sensor selection, not its owner’s reporting. Also enable reporting on the body, owning articulation link, or articulation root to avoid depending on reports from the other actor in each pair. The child remains a row but reads zero when neither actor reports matching contacts. Configure reporting settings on the reporting actor or articulation root; a standalone static collider is its own actor and enables reporting on CPU simulation and GPU dynamics with CPU readback. On DirectGPU its sensor row remains but reads zero force.

filters: Sequence[str | Sequence[int]]#

Alias for field number 1

sensors: str | Sequence[int]#

Alias for field number 0

class ovphysx.types.GlobalConfigKey(
value,
names=_not_given,
*values,
module=None,
qualname=None,
type=None,
start=1,
boundary=None,
)#

Bases: IntEnum

Process-global configuration keys.

COLLISION_CONE_CUSTOM_GEOMETRY = 1#
COLLISION_CYLINDER_CUSTOM_GEOMETRY = 2#
COOKED_COLLIDER_CACHE_DIRECTORY = 7#
CPU_ONLY = 9#
DEFAULT_LOG_OUTPUT = 11#
DISABLE_CONTACT_PROCESSING = 0#
LOG_LEVEL = 10#
NUM_THREADS = 3#
OVD_RECORDING_CAPABLE = 12#
OVSTAGE_READ_POOL_MAX_MB = 5#
PROFILER_BACKEND = 6#
PROFILER_OUTPUT_PATH = 8#
SCENE_MULTI_GPU_MODE = 4#
class ovphysx.types.LogLevel(
value,
names=_not_given,
*values,
module=None,
qualname=None,
type=None,
start=1,
boundary=None,
)#

Bases: IntEnum

Log level for ovphysx output. Mirrors ovphysx_log_level_t.

DEFAULT restores the effective WARNING threshold. DEFAULT and NONE configure logging but are never delivered as callback severities.

DEFAULT = 0#
ERROR = 4#
INFO = 2#
NONE = 5#
VERBOSE = 1#
WARNING = 3#
class ovphysx.types.ObjectScope(
value,
names=_not_given,
*values,
module=None,
qualname=None,
type=None,
start=1,
boundary=None,
)#

Bases: IntEnum

Output query scope. Mirrors ovphysx_object_scope_t.

ACTIVE is single-frame (the active set is recomputed each step). ALL is stable until a structural change.

ACTIVE = 1#
ALL = 0#
class ovphysx.types.ObjectType(
value,
names=_not_given,
*values,
module=None,
qualname=None,
type=None,
start=1,
boundary=None,
)#

Bases: IntEnum

TensorAPI object classification. Mirrors ovphysx_object_type_t in the legacy C header.

Deprecated since version 0.6.0: Object-type lookup via PhysX.get_object_type() is deprecated.

Returned by PhysX.get_object_type(). Standalone UsdPhysics joints are JOINT; plugin-registered custom joints are CUSTOM_JOINT; articulation joints are ARTICULATION_JOINT. Native addresses for those kinds are the physxPointer column on the matching SimObjectType.

ARTICULATION = 2#
ARTICULATION_JOINT = 5#
CUSTOM_JOINT = 7#
INVALID = 0#
JOINT = 6#
RIGID_BODY = 1#
class ovphysx.types.ProfilerBackend(
value,
names=_not_given,
*values,
module=None,
qualname=None,
type=None,
start=1,
boundary=None,
)#

Bases: IntEnum

Profiler backend selection. Mirrors ovphysx_profiler_backend_t.

The value of GlobalConfigKey.PROFILER_BACKEND.

NONE = 0#
NVTX = 1#
TRACE = 2#
class ovphysx.types.SceneQueryGeometryType(
value,
names=_not_given,
*values,
module=None,
qualname=None,
type=None,
start=1,
boundary=None,
)#

Bases: IntEnum

Geometry type for sweep/overlap queries. Mirrors ovphysx_scene_query_geometry_type_t.

Deprecated since version 0.6.0: Scene queries are deprecated.

BOX = 1#
SHAPE = 2#
SPHERE = 0#
class ovphysx.types.SceneQueryMode(
value,
names=_not_given,
*values,
module=None,
qualname=None,
type=None,
start=1,
boundary=None,
)#

Bases: IntEnum

Scene query hit mode. Mirrors ovphysx_scene_query_mode_t.

Deprecated since version 0.6.0: Scene queries are deprecated.

ALL = 2#
ANY = 1#
CLOSEST = 0#
class ovphysx.types.SimObjectType(
value,
names=_not_given,
*values,
module=None,
qualname=None,
type=None,
start=1,
boundary=None,
)#

Bases: IntEnum

Query target for the physics output read.

Mirrors ovphysx_query_target_t, including its numbering rules: explicit contiguous values from 0, new entries appended with the next integer, and no gaps or renumbering. DEBUG_RENDER is an instance target, not a simulated prim. Its value is pinned like the others; later types append after it.

This is a separate enum domain from the TensorBindings ObjectType. In particular, SimObjectType.ARTICULATION is 9 while ObjectType.ARTICULATION is 2.

ARTICULATION = 9#
ARTICULATION_JOINT = 2#
CHARACTER_CONTROLLER = 12#
COMPOUND_SHAPE = 17#
CONTACT_SENSOR = 11#
CUSTOM_JOINT = 20#
DEBUG_RENDER = 23#
DEFORMABLE_MATERIAL = 10#
DEFORMABLE_SURFACE = 5#
DEFORMABLE_VOLUME = 4#
FIXED_TENDON = 7#
JOINT = 19#
PARTICLE_SET = 6#
PARTICLE_SYSTEM = 21#
PHYSICS = 22#
PHYSX_MATERIAL = 15#
RIGID_ACTOR = 18#
RIGID_BODY = 0#
SCENE = 14#
SDF_SHAPE = 24#
SHAPE = 16#
SPATIAL_TENDON = 8#
VEHICLE = 13#
VEHICLE_WHEEL = 3#
class ovphysx.types.TensorType(
value,
names=_not_given,
*values,
module=None,
qualname=None,
type=None,
start=1,
boundary=None,
)#

Bases: IntEnum

Tensor type identifiers for TensorBindingsAPI.

Deprecated since version 0.6.0: The tensor-binding API is deprecated. Use PhysX.read() for reads and PhysX.write() for writes.

Values match ovphysx_tensor_type_t in ovphysx_types.h. IntEnum members compare equal to plain ints, so they pass directly to the C API without conversion.

ARTICULATION_BODY_COM_POSE = 61#
ARTICULATION_BODY_DISABLE_GRAVITY = 65#
ARTICULATION_BODY_INERTIA = 62#
ARTICULATION_BODY_INV_INERTIA = 64#
ARTICULATION_BODY_INV_MASS = 63#
ARTICULATION_BODY_MASS = 60#
ARTICULATION_CENTROIDAL_MOMENTUM = 14#
ARTICULATION_CONTACT_OFFSET = 111#
ARTICULATION_CORIOLIS_AND_CENTRIFUGAL_FORCE = 72#
ARTICULATION_DOF_ACTUATION_FORCE = 34#
ARTICULATION_DOF_ARMATURE = 40#
ARTICULATION_DOF_DAMPING = 36#
ARTICULATION_DOF_DRIVE_MODEL = 42#
ARTICULATION_DOF_DRIVE_TYPE = 43#
ARTICULATION_DOF_FRICTION_PROPERTIES = 41#
ARTICULATION_DOF_LIMIT = 37#
ARTICULATION_DOF_MAX_FORCE = 39#
ARTICULATION_DOF_MAX_VELOCITY = 38#
ARTICULATION_DOF_POSITION = 30#
ARTICULATION_DOF_POSITION_TARGET = 32#
ARTICULATION_DOF_PROJECTED_JOINT_FORCE = 75#
ARTICULATION_DOF_STIFFNESS = 35#
ARTICULATION_DOF_VELOCITY = 31#
ARTICULATION_DOF_VELOCITY_TARGET = 33#
ARTICULATION_FIXED_TENDON_DAMPING = 81#
ARTICULATION_FIXED_TENDON_LIMIT = 83#
ARTICULATION_FIXED_TENDON_LIMIT_STIFFNESS = 82#
ARTICULATION_FIXED_TENDON_OFFSET = 85#
ARTICULATION_FIXED_TENDON_REST_LENGTH = 84#
ARTICULATION_FIXED_TENDON_STIFFNESS = 80#
ARTICULATION_GRAVITY_FORCE = 73#
ARTICULATION_JACOBIAN = 70#
ARTICULATION_MASS_CENTER_LOCAL = 13#
ARTICULATION_MASS_CENTER_WORLD = 12#
ARTICULATION_MASS_MATRIX = 71#
ARTICULATION_REST_OFFSET = 112#
ARTICULATION_ROOT_POSE = 10#
ARTICULATION_ROOT_VELOCITY = 11#
ARTICULATION_SHAPE_FRICTION_AND_RESTITUTION = 110#
ARTICULATION_SPATIAL_TENDON_DAMPING = 91#
ARTICULATION_SPATIAL_TENDON_LIMIT_STIFFNESS = 92#
ARTICULATION_SPATIAL_TENDON_OFFSET = 93#
ARTICULATION_SPATIAL_TENDON_STIFFNESS = 90#
DEFORMABLE_COLLISION_ELEMENT_INDICES = 125#
DEFORMABLE_MATERIAL_BENDING_DAMPING = 136#
DEFORMABLE_MATERIAL_BENDING_STIFFNESS = 134#
DEFORMABLE_MATERIAL_DYNAMIC_FRICTION = 130#
DEFORMABLE_MATERIAL_ELASTICITY_DAMPING = 133#
DEFORMABLE_MATERIAL_POISSONS_RATIO = 132#
DEFORMABLE_MATERIAL_THICKNESS = 135#
DEFORMABLE_MATERIAL_YOUNGS_MODULUS = 131#
DEFORMABLE_REST_NODAL_POSITION = 123#
DEFORMABLE_SIM_ELEMENT_INDICES = 124#
DEFORMABLE_SIM_KINEMATIC_TARGET = 122#
DEFORMABLE_SIM_NODAL_POSITION = 120#
DEFORMABLE_SIM_NODAL_VELOCITY = 121#
INVALID = 0#
RIGID_BODY_ACCELERATION = 6#
RIGID_BODY_COM_POSE = 5#
RIGID_BODY_CONTACT_OFFSET = 101#
RIGID_BODY_DISABLE_GRAVITY = 103#
RIGID_BODY_DISABLE_SIMULATION = 9#
RIGID_BODY_FORCE = 50#
RIGID_BODY_INERTIA = 4#
RIGID_BODY_INV_INERTIA = 8#
RIGID_BODY_INV_MASS = 7#
RIGID_BODY_MASS = 3#
RIGID_BODY_POSE = 1#
RIGID_BODY_REST_OFFSET = 102#
RIGID_BODY_SHAPE_FRICTION_AND_RESTITUTION = 100#
RIGID_BODY_VELOCITY = 2#
RIGID_BODY_WRENCH = 51#
SURFACE_DEFORMABLE_REST_POSITION = 143#
SURFACE_DEFORMABLE_SIM_ELEMENT_INDICES = 144#
SURFACE_DEFORMABLE_SIM_POSITION = 140#
SURFACE_DEFORMABLE_SIM_VELOCITY = 141#

DLPack Tensor Structures#

DLPack tensor structures for zero-copy data interchange.

This module provides ctypes wrappers for the vendored DLPack C header, enabling efficient data sharing between the C library and Python without copying.

NOTE: This file is NOT copied from another repo. It is a hand-written Python/ctypes mirror of the C structs defined in ovphysx/dlpack/dlpack.h (which itself is the upstream header from https://github.com/dmlc/dlpack). When the vendored C header is updated, this file must be updated to match.

class ovphysx.dlpack.DLDataType#

Bases: Structure

Descriptor of data type for elements of DLTensor.

TYPE_MAP = {'bfloat16': (4, 16, 1), 'float16': (2, 16, 1), 'float32': (2, 32, 1), 'float32x4': (2, 32, 4), 'float64': (2, 64, 1), 'int16': (0, 16, 1), 'int32': (0, 32, 1), 'int64': (0, 64, 1), 'int8': (0, 8, 1), 'uint16': (1, 16, 1), 'uint32': (1, 32, 1), 'uint64': (1, 64, 1), 'uint8': (1, 8, 1), 'uint8x4': (1, 8, 4)}#
bits#

Structure/Union member

code#

Structure/Union member

lanes#

Structure/Union member

class ovphysx.dlpack.DLDataTypeCode#

Bases: c_ubyte

An integer that encodes the category of DLTensor elements’ data type.

kDLBfloat = 4#
kDLBool = 6#
kDLComplex = 5#
kDLFloat = 2#
kDLFloat4_e2m1fn = 17#
kDLFloat6_e2m3fn = 15#
kDLFloat6_e3m2fn = 16#
kDLFloat8_e3m4 = 7#
kDLFloat8_e4m3 = 8#
kDLFloat8_e4m3b11fnuz = 9#
kDLFloat8_e4m3fn = 10#
kDLFloat8_e4m3fnuz = 11#
kDLFloat8_e5m2 = 12#
kDLFloat8_e5m2fnuz = 13#
kDLFloat8_e8m0fnu = 14#
kDLInt = 0#
kDLOpaqueHandle = 3#
kDLUInt = 1#
class ovphysx.dlpack.DLDevice#

Bases: Structure

Represents the device where DLTensor memory is allocated.

device_id#

Structure/Union member

device_type#

Structure/Union member

class ovphysx.dlpack.DLDeviceType#

Bases: c_long

The enum that encodes the type of the device where DLTensor memory is allocated.

kDLCPU = 1#
kDLCUDA = 2#
kDLCUDAHost = 3#
kDLCUDAManaged = 13#
kDLExtDev = 12#
kDLHexagon = 16#
kDLMAIA = 17#
kDLMetal = 8#
kDLOneAPI = 14#
kDLOpenCL = 4#
kDLROCM = 10#
kDLROCMHost = 11#
kDLTrn = 18#
kDLVPI = 9#
kDLVulkan = 7#
kDLWebGPU = 15#
class ovphysx.dlpack.DLManagedTensor#

Bases: Structure

C structure for managed DLPack tensor.

deleter#

Structure/Union member

dl_tensor#

Structure/Union member

manager_ctx#

Structure/Union member

class ovphysx.dlpack.DLTensor#

Bases: Structure

Plain C Tensor object, does not manage memory.

byte_offset#

Structure/Union member

data#

Structure/Union member

device#

Structure/Union member

dtype#

Structure/Union member

ndim#

Structure/Union member

shape#

Structure/Union member

strides#

Structure/Union member

Physics Utilities#

USD physics authoring utilities.

ovphysx.api.PhysX simulates a stage; this subpackage mostly builds one. Its bulk is a pure-Python layer over pxr that authors the geometry, xform ops and physics API schemas a scene needs, so a caller does not have to spell out a rigid body’s collider, mass and transform by hand for every prim. The one exception is simulation, described at the end.

The helpers come from omni.physx.scripts, whose names mixed camelCase and snake_case. Every name here is snake_case, so setCollider is set_collider() and createAPISchemaPropertyCache is create_api_schema_property_cache(). Aliasing the subpackage on import keeps a ported snippet close to its original shape:

from ovphysx import utils as physicsUtils
physicsUtils.add_rigid_box(stage, "/World/box", position=Gf.Vec3f(0, 0, 5))

Eight camelCase spellings survive as deprecated aliases: setCollider, setRigidBody, removeCollider, removePhysics, removeRigidBodySubtree, hasSchema, createJoint and extractTriangleSurfaceFromTetra. Each forwards to the new spelling and raises a DeprecationWarning naming both, and each is reachable as ovphysx.utils.<name> and by explicit import. None is in __all__, so from ovphysx.utils import * and the rendered documentation show the new spellings only. No other camelCase name is kept.

Keyword parameters are snake_case on the same terms, so setCollider(prim, approximationShape=...) becomes set_collider(prim, approximation_shape=...). Three old spellings stay accepted, being the ones on the helpers above: approximationShape on set_collider() and set_rigid_body(), and schemaName on has_schema(). Each raises a DeprecationWarning naming both spellings; passing both in one call raises TypeError.

Importing this subpackage does not load the ovphysx native library, contact a USD resolver or start a simulation, so it is usable in a process that only authors USD. Diagnostics go through the standard logging module under the ovphysx.utils logger hierarchy.

The authoring helpers need pxr. An authoring process supplies its own stock usd-core, and this subpackage is reached with an explicit import ovphysx.utils so that import ovphysx keeps working for simulation-only users who have no pxr.

pxr is required only once an authoring name is actually touched, not to import this subpackage. Submodules load on first attribute access, so from ovphysx.utils import step_and_write_to_ovstage resolves in a process that has ovstage but no USD at all – which is what the output_read sample does.

PhysX schemas are codeless, so PhysX API schemas are applied by identifier and their properties authored by name; core UsdPhysics schemas still use their typed bindings. Register the schemas before opening any stage:

from ovphysx.utils import codeless
codeless.register_schemas()

Refer to codeless for the registration rules, which are strict about ordering and fail silently when ignored.

The submodules group the surface by theme, and every name is also re-exported here, so both ovphysx.utils.shapes.add_rigid_box and ovphysx.utils.add_rigid_box resolve:

  • codeless - registration and access for the codeless PhysX schemas

  • schema - schema registry introspection, API schema property snapshot and restore

  • transform - xform op stacks, basis vectors, joint-relative transforms

  • paths - collision-free stage paths for a prim about to be defined

  • shapes - cube, sphere, capsule, cylinder, cone and xform constructors, plain, collider and rigid-body flavored

  • planes - ground planes and sized quad planes

  • joints - joints between two prims or between a prim and the world

  • materials - physics materials and their binding to prims

  • filtering - collision groups and filtered pairs

  • authoring - mass, force, physics scenes and the collider and rigid-body API sets on prims that already exist

  • mesh - procedural meshes, triangle and tetrahedron mesh math

  • particles - particle systems, particle sets, PBD materials

  • deformable - volume and surface deformable bodies and their materials

  • simulation - stepping a running simulation and writing its output back to an attached ovstage Stage

  • constants - shared tokens and limits

ovphysx.utils is the home for any supported ovphysx helper that does not belong in the top-level API, a wider remit than USD authoring alone: simulation is the one such submodule today. A submodule of that kind - one that drives a simulation rather than authoring a stage - must import runtime dependencies such as ovstage, warp and numpy inside its functions rather than at module scope, and reach ovphysx.api either the same way or under if TYPE_CHECKING:, so that import ovphysx.utils keeps needing nothing beyond pxr and the standard library and still loads no native library. Such a helper may need ovstage and a live PhysX instance when called; only the import-time guarantee is subpackage-wide.

Utilities are grouped by submodule. Except for the codeless schema helpers, public names are also available directly from ovphysx.utils.

Codeless schema access#

Not flat re-exported. Import it as from ovphysx.utils import codeless.

Authoring with codeless PhysX USD schemas.

The external physx-usd-schemas package supplies codeless artifacts: a plugInfo.json and generatedSchema.usda per module. API schemas are applied by their schema identifier and their properties are reached by name:

from ovphysx.utils import codeless

codeless.apply_api(prim, "PhysxRigidBodyAPI")
codeless.set_attr(prim, "physxRigidBody:disableGravity", True)

Multiple-apply schemas take an instance name, which becomes the middle component of the property path:

codeless.apply_api(prim, "PhysxCookedDataAPI", "convexHull")
codeless.set_attr(prim, codeless.instanced_name("physxCookedData", "convexHull", "buffer"), buf)

Registration comes first#

The schemas must be registered with the USD runtime before anything in the process opens a stage or queries the schema registry. USD builds that registry once, on first access, and never rebuilds it, so a late registration is silently ineffective and the process it happened in cannot be repaired: there is no reload, no reset, and a second register_schemas() call reports success while changing nothing. Getting the order wrong costs a restart.

ovphysx does not load USD or register schemas on import. In a stock usd-core authoring process, call register_schemas() as the first thing in the program, or preset PXR_PLUGINPATH_NAME before the process starts. Presetting the environment variable is the only route that also works inside a host that has already initialized USD, because USD reads it while constructing the registry rather than afterwards. Refer to docs/physics_schemas.md.

The helpers here turn USD’s “invalid schema” error into one that names the likely cause.

exception ovphysx.utils.codeless.CodelessSchemaError#

Bases: RuntimeError

A codeless PhysX schema could not be applied, removed or authored.

ovphysx.utils.codeless.apply_api(
prim: pxr.Usd.Prim,
identifier: str,
instance_name: str | None = None,
) → None#

Apply a codeless API schema to a prim by schema identifier.

Parameters:
  • prim – The prim to apply the API to.

  • identifier – The schema identifier, e.g. "PhysxRigidBodyAPI".

  • instance_name – The instance name for a multiple-apply schema, e.g. "convexHull" for PhysxCookedDataAPI. Omit for single-apply schemas.

Raises:

CodelessSchemaError – If the API could not be applied. The message distinguishes the two usual causes – the schemas not being registered, or the identifier not naming a known API schema – from USD refusing to author a schema it knows.

ovphysx.utils.codeless.get_attr(prim: pxr.Usd.Prim, name: str) → pxr.Usd.Attribute#

Return a prim attribute by name, with a readable error when it is missing.

Parameters:
  • prim – The prim to read from.

  • name – The full property name, e.g. "physxRigidBody:disableGravity".

Raises:

CodelessSchemaError – If the prim is invalid or has no such attribute. Usually the owning API was not applied first, or the schemas are unregistered.

ovphysx.utils.codeless.instanced_name(
prefix: str,
instance_name: str,
property_name: str,
) → str#

Build the property name of a multiple-apply schema instance.

For example instanced_name("physxCookedData", "convexHull", "buffer") gives "physxCookedData:convexHull:buffer".

ovphysx.utils.codeless.register_schemas(verify: bool = False)#

Register the external codeless PhysX schemas with the active USD runtime.

Intended for authoring processes running on a stock usd-core. Call it before opening any stage or querying the schema registry; USD builds that registry once and a later call cannot repair it, in this process or by any other means short of a restart.

A late call gives no sign of it on its own. RegisterPlugins still reports the plugin roots as registered and Tf.Type.FindByName still resolves the schema types; only applying an API fails, arbitrarily far away. Pass verify to convert that into an immediate error.

Idempotent: USD ignores a plugin root it has already seen.

Parameters:

verify – Confirm the schemas reached the schema registry and raise if they did not. Off by default because the check is not free: the only way to ask is to query the schema registry, which builds it, so a verified call has to be the last plugin registration in the process. Leave it off where another USD component registers plugins after ovphysx.

Returns:

The list of registered Plug.Plugin objects, which is empty when the schemas were already registered.

Raises:
  • FileNotFoundError – If the external provider or its resources are missing. Install physx-usd-schemas from PyPI.

  • CodelessSchemaError – If verify is set and any of the schema roots did not reach the schema registry, because something built it first or because its resources are missing.

ovphysx.utils.codeless.remove_api(
prim: pxr.Usd.Prim,
identifier: str,
instance_name: str | None = None,
) → bool#

Remove a codeless API schema from a prim by schema identifier.

With the schemas registered, removing an API that was never applied is not an error; USD reports it as a no-op and this returns its result unchanged, so a whole family of mutually exclusive APIs can be stripped without asking which one is there.

The returned bool is USD’s answer to whether it authored the removal on the current edit target, not a promise that the API is gone: an opinion on a stronger layer survives a successful removal on a weaker one. A removal USD refuses on a schema it knows – on a layer that is not editable, for instance – is False too, on the same terms as try_apply_api().

Parameters:
  • prim – The prim to strip.

  • identifier – The schema identifier.

  • instance_name – The instance name for a multiple-apply schema.

Returns:

Whether USD reports the removal as successful.

Raises:

CodelessSchemaError – If the prim is invalid or USD cannot resolve the call at all, on the same terms as try_apply_api().

ovphysx.utils.codeless.schema_is_registered() → bool#

Whether the codeless PhysX schemas are visible to the schema registry.

Returns False if either the PhysX or Omni deformable plugin is missing.

Note that calling this builds the schema registry if it does not exist yet, which locks out every later schema plugin registration in the process, ovphysx’s and any other library’s alike. Register first, then query.

ovphysx.utils.codeless.set_attr(prim: pxr.Usd.Prim, name: str, value) → pxr.Usd.Attribute#

Author a prim attribute by name.

The attribute must already be declared, which for a codeless schema means its API was applied first. This is the codeless replacement for the typed api.CreateFooAttr(value) calls.

Parameters:
  • prim – The prim to author on.

  • name – The full property name.

  • value – The value to set.

Returns:

The authored attribute.

Raises:

CodelessSchemaError – If the attribute does not exist or cannot be set.

ovphysx.utils.codeless.set_attrs(prim: pxr.Usd.Prim, values: dict) → None#

Author several attributes, skipping the ones whose value is None.

The authoring helpers expose every schema attribute as an optional keyword defaulting to None, so that an unsupplied attribute keeps its schema fallback instead of being pinned to a value chosen by the helper. This applies that convention in one call.

Parameters:
  • prim – The prim to author on.

  • values – A mapping of full property name to value. None values are skipped.

Raises:

CodelessSchemaError – If the prim is invalid or an attribute cannot be set.

ovphysx.utils.codeless.set_rel(
prim: pxr.Usd.Prim,
name: str,
targets,
) → pxr.Usd.Relationship#

Set a relationship’s targets by name.

Parameters:
  • prim – The prim to author on.

  • name – The full relationship name, e.g. "physxParticle:particleSystem".

  • targets – A single target path or a list of them.

Raises:

CodelessSchemaError – If the prim has no such relationship, or the targets could not be set.

ovphysx.utils.codeless.try_apply_api(
prim: pxr.Usd.Prim,
identifier: str,
instance_name: str | None = None,
) → bool#

Apply a codeless API schema, returning whether USD accepted it.

The bool-returning half of apply_api(), for a caller that already reports a refused application its own way – the deformable helpers warn and return False rather than raising.

A refusal is USD declining to author a schema it knows, as for a prim on a layer that is not editable. USD reports it either by answering False or by raising, and both come back as False here. The two causes below are not refusals: USD cannot resolve the identifier at all, so it has nothing to answer about.

Parameters:
  • prim – The prim to apply the API to.

  • identifier – The schema identifier, e.g. "PhysxRigidBodyAPI".

  • instance_name – The instance name for a multiple-apply schema.

Raises:

CodelessSchemaError – If the prim is invalid or USD cannot resolve the call at all – the schemas not being registered, the identifier not naming a known API schema, or the instance name contradicting the one it does name.

Shape constructors#

Shape constructors: geometry, colliders and rigid bodies in one call.

Every shape comes in three flavors. The plain add_* helper defines the UsdGeom prim with a display color and a translate-orient-scale xform op stack; add_collider_* additionally applies UsdPhysics.CollisionAPI; and add_rigid_* applies UsdPhysics.RigidBodyAPI and UsdPhysics.MassAPI with a density and initial velocities on top of that. Each is a one-line way to put a falling box or a static ramp on a stage.

The physics APIs are applied here directly rather than through set_collider(), so a shape carries a bare collision API and no mesh approximation: these are all analytic UsdGeom shapes, for which an approximation has nothing to describe. Reach for set_collider instead when the prim is a mesh or already exists.

ovphysx.utils.shapes.add_box(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
size: pxr.Gf.Vec3f = Gf.Vec3f(1.0),
position: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
orientation: pxr.Gf.Quatf = Gf.Quatf(1.0),
color: pxr.Gf.Vec3f = Gf.Vec3f(1.0),
) → pxr.Usd.Prim#

Add UsdGeom.Cube to the stage.

Parameters:
  • stage – The Usd.Stage to add cube.

  • path – The desired cube path.

  • size – The size of the cube.

  • position – The position where the cube should be placed in stage.

  • orientation – The cube orientation.

  • color – The color of the mesh.

ovphysx.utils.shapes.add_capsule(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
radius: float = 1.0,
height: float = 1.0,
axis: str = 'Y',
position: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
orientation: pxr.Gf.Quatf = Gf.Quatf(1.0),
color: pxr.Gf.Vec3f = Gf.Vec3f(1.0),
) → pxr.Usd.Prim#

Add UsdGeom.Capsule to the stage.

The extent authored here is the one UsdGeom.Capsule’s own schema computation produces, so it follows axis and reaches height / 2 + radius along it – the cylindrical section plus a hemispherical cap at each end – and radius across it.

Parameters:
  • stage – The Usd.Stage to add capsule.

  • path – The desired capsule path.

  • radius – The radius of the capsule.

  • height – The height of the capsule.

  • axis – The axis of the capsule.

  • position – The position where the capsule should be placed in stage.

  • orientation – The capsule orientation.

  • color – The color of the mesh.

ovphysx.utils.shapes.add_collider_box(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
size: pxr.Gf.Vec3f = Gf.Vec3f(1.0),
position: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
orientation: pxr.Gf.Quatf = Gf.Quatf(1.0),
color: pxr.Gf.Vec3f = Gf.Vec3f(1.0),
) → pxr.Usd.Prim#

Add UsdGeom.Cube to the stage and add physics collider API to it.

Parameters:
  • stage – The Usd.Stage to add cube.

  • path – The desired cube path.

  • size – The size of the cube.

  • position – The position where the cube should be placed in stage.

  • orientation – The cube orientation.

  • color – The color of the mesh.

ovphysx.utils.shapes.add_collider_capsule(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
radius: float = 1.0,
height: float = 1.0,
axis: str = 'Y',
position: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
orientation: pxr.Gf.Quatf = Gf.Quatf(1.0),
color: pxr.Gf.Vec3f = Gf.Vec3f(1.0),
) → pxr.Usd.Prim#

Add UsdGeom.Capsule to the stage and add physics collider API to it.

Parameters:
  • stage – The Usd.Stage to add capsule.

  • path – The desired capsule path.

  • radius – The radius of the capsule.

  • height – The height of the capsule.

  • axis – The axis of the capsule.

  • position – The position where the capsule should be placed in stage.

  • orientation – The capsule orientation.

  • color – The color of the mesh.

ovphysx.utils.shapes.add_collider_cone(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
radius: float = 1.0,
height: float = 1.0,
axis: str = 'Y',
position: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
orientation: pxr.Gf.Quatf = Gf.Quatf(1.0),
color: pxr.Gf.Vec3f = Gf.Vec3f(1.0),
) → pxr.Usd.Prim#

Add UsdGeom.Cone to the stage and add physics collider API to it.

Parameters:
  • stage – The Usd.Stage to add cone.

  • path – The desired cone path.

  • radius – The radius of the cone.

  • height – The height of the cone.

  • axis – The axis of the cone.

  • position – The position where the cone should be placed in stage.

  • orientation – The cone orientation.

  • color – The color of the mesh.

ovphysx.utils.shapes.add_collider_cube(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
size: pxr.Gf.Vec3f = Gf.Vec3f(1.0),
position: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
orientation: pxr.Gf.Quatf = Gf.Quatf(1.0),
color: pxr.Gf.Vec3f = Gf.Vec3f(1.0),
) → pxr.Usd.Prim#

Add UsdGeom.Cube to the stage and add physics collider API to it.

Parameters:
  • stage – The Usd.Stage to add cube.

  • path – The desired cube path.

  • size – The size of the cube.

  • position – The position where the cube should be placed in stage.

  • orientation – The cube orientation.

  • color – The color of the mesh.

ovphysx.utils.shapes.add_collider_cylinder(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
radius: float = 1.0,
height: float = 1.0,
axis: str = 'Y',
position: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
orientation: pxr.Gf.Quatf = Gf.Quatf(1.0),
color: pxr.Gf.Vec3f = Gf.Vec3f(1.0),
) → pxr.Usd.Prim#

Add UsdGeom.Cylinder to the stage and add physics collider API to it.

Parameters:
  • stage – The Usd.Stage to add cylinder.

  • path – The desired cylinder path.

  • radius – The radius of the cylinder.

  • height – The height of the cylinder.

  • axis – The axis of the cylinder.

  • position – The position where the cylinder should be placed in stage.

  • orientation – The cylinder orientation.

  • color – The color of the mesh.

ovphysx.utils.shapes.add_collider_sphere(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
radius: float = 1.0,
position: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
orientation: pxr.Gf.Quatf = Gf.Quatf(1.0),
color: pxr.Gf.Vec3f = Gf.Vec3f(1.0),
) → pxr.Usd.Prim#

Add UsdGeom.Sphere to the stage and add physics collider API to it.

Parameters:
  • stage – The Usd.Stage to add sphere.

  • path – The desired sphere path.

  • radius – The radius of the sphere.

  • position – The position where the sphere should be placed in stage.

  • orientation – The sphere orientation.

  • color – The color of the mesh.

ovphysx.utils.shapes.add_cone(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
radius: float = 1.0,
height: float = 1.0,
axis: str = 'Y',
position: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
orientation: pxr.Gf.Quatf = Gf.Quatf(1.0),
color: pxr.Gf.Vec3f = Gf.Vec3f(1.0),
) → pxr.Usd.Prim#

Add UsdGeom.Cone to the stage.

The extent authored here is the one UsdGeom.Cone’s own schema computation produces, so it follows axis and reaches height / 2 along it and radius across it.

Parameters:
  • stage – The Usd.Stage to add cone.

  • path – The desired cone path.

  • radius – The radius of the cone.

  • height – The height of the cone.

  • axis – The axis of the cone.

  • position – The position where the cone should be placed in stage.

  • orientation – The cone orientation.

  • color – The color of the mesh.

ovphysx.utils.shapes.add_cube(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
size: pxr.Gf.Vec3f = Gf.Vec3f(1.0),
position: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
orientation: pxr.Gf.Quatf = Gf.Quatf(1.0),
color: pxr.Gf.Vec3f = Gf.Vec3f(1.0),
) → pxr.Usd.Prim#

Add UsdGeom.Cube to the stage.

Parameters:
  • stage – The Usd.Stage to add cube.

  • path – The desired cube path.

  • size – The size of the cube.

  • position – The position where the cube should be placed in stage.

  • orientation – The cube orientation.

  • color – The color of the mesh.

ovphysx.utils.shapes.add_cylinder(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
radius: float = 1.0,
height: float = 1.0,
axis: str = 'Y',
position: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
orientation: pxr.Gf.Quatf = Gf.Quatf(1.0),
color: pxr.Gf.Vec3f = Gf.Vec3f(1.0),
) → pxr.Usd.Prim#

Add UsdGeom.Cylinder to the stage.

The extent authored here is the one UsdGeom.Cylinder’s own schema computation produces, so it follows axis and reaches height / 2 along it and radius across it.

Parameters:
  • stage – The Usd.Stage to add cylinder.

  • path – The desired cylinder path.

  • radius – The radius of the cylinder.

  • height – The height of the cylinder.

  • axis – The axis of the cylinder.

  • position – The position where the cylinder should be placed in stage.

  • orientation – The cylinder orientation.

  • color – The color of the mesh.

ovphysx.utils.shapes.add_rigid_box(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
size: pxr.Gf.Vec3f = Gf.Vec3f(1.0),
position: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
orientation: pxr.Gf.Quatf = Gf.Quatf(1.0),
color: pxr.Gf.Vec3f = Gf.Vec3f(1.0),
density: float = 1.0,
lin_velocity: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
ang_velocity: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
) → pxr.Usd.Prim#

Add UsdGeom.Cube to the stage and add physics rigid body and collider API to it.

A density of 0.0 still applies UsdPhysics.RigidBodyAPI and UsdPhysics.MassAPI; it is not a request for a static collider. Use add_collider_box for that.

Parameters:
  • stage – The Usd.Stage to add cube.

  • path – The desired cube path.

  • size – The size of the cube.

  • position – The position where the cube should be placed in stage.

  • orientation – The cube orientation.

  • color – The color of the mesh.

  • density – The density of the rigid body.

  • lin_velocity – The initial linear velocity of the rigid body.

  • ang_velocity – The initial angular velocity of the rigid body.

ovphysx.utils.shapes.add_rigid_capsule(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
radius: float = 1.0,
height: float = 1.0,
axis: str = 'Y',
position: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
orientation: pxr.Gf.Quatf = Gf.Quatf(1.0),
color: pxr.Gf.Vec3f = Gf.Vec3f(1.0),
density: float = 1.0,
lin_velocity: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
ang_velocity: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
) → pxr.Usd.Prim#

Add UsdGeom.Capsule to the stage and add physics rigid body and collider API to it.

A density of 0.0 still applies UsdPhysics.RigidBodyAPI and UsdPhysics.MassAPI; it is not a request for a static collider. Use add_collider_capsule for that.

Parameters:
  • stage – The Usd.Stage to add capsule.

  • path – The desired capsule path.

  • radius – The radius of the capsule.

  • height – The height of the capsule.

  • axis – The axis of the capsule.

  • position – The position where the capsule should be placed in stage.

  • orientation – The capsule orientation.

  • color – The color of the mesh.

  • density – The density of the rigid body.

  • lin_velocity – The initial linear velocity of the rigid body.

  • ang_velocity – The initial angular velocity of the rigid body.

ovphysx.utils.shapes.add_rigid_cone(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
radius: float = 1.0,
height: float = 1.0,
axis: str = 'Y',
position: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
orientation: pxr.Gf.Quatf = Gf.Quatf(1.0),
color: pxr.Gf.Vec3f = Gf.Vec3f(1.0),
density: float = 1.0,
lin_velocity: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
ang_velocity: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
) → pxr.Usd.Prim#

Add UsdGeom.Cone to the stage and add physics rigid body and collider API to it.

A density of 0.0 still applies UsdPhysics.RigidBodyAPI and UsdPhysics.MassAPI; it is not a request for a static collider. Use add_collider_cone for that.

Parameters:
  • stage – The Usd.Stage to add cone.

  • path – The desired cone path.

  • radius – The radius of the cone.

  • height – The height of the cone.

  • axis – The axis of the cone.

  • position – The position where the cone should be placed in stage.

  • orientation – The cone orientation.

  • color – The color of the mesh.

  • density – The density of the rigid body.

  • lin_velocity – The initial linear velocity of the rigid body.

  • ang_velocity – The initial angular velocity of the rigid body.

ovphysx.utils.shapes.add_rigid_cube(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
size: pxr.Gf.Vec3f = Gf.Vec3f(1.0),
position: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
orientation: pxr.Gf.Quatf = Gf.Quatf(1.0),
color: pxr.Gf.Vec3f = Gf.Vec3f(1.0),
density: float = 1.0,
lin_velocity: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
ang_velocity: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
) → pxr.Usd.Prim#

Add UsdGeom.Cube to the stage and add physics rigid body and collider API to it.

A density of 0.0 still applies UsdPhysics.RigidBodyAPI and UsdPhysics.MassAPI; it is not a request for a static collider. Use add_collider_cube for that.

Parameters:
  • stage – The Usd.Stage to add cube.

  • path – The desired cube path.

  • size – The size of the cube.

  • position – The position where the cube should be placed in stage.

  • orientation – The cube orientation.

  • color – The color of the mesh.

  • density – The density of the rigid body.

  • lin_velocity – The initial linear velocity of the rigid body.

  • ang_velocity – The initial angular velocity of the rigid body.

ovphysx.utils.shapes.add_rigid_cylinder(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
radius: float = 1.0,
height: float = 1.0,
axis: str = 'Y',
position: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
orientation: pxr.Gf.Quatf = Gf.Quatf(1.0),
color: pxr.Gf.Vec3f = Gf.Vec3f(1.0),
density: float = 1.0,
lin_velocity: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
ang_velocity: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
) → pxr.Usd.Prim#

Add UsdGeom.Cylinder to the stage and add physics rigid body and collider API to it.

A density of 0.0 still applies UsdPhysics.RigidBodyAPI and UsdPhysics.MassAPI; it is not a request for a static collider. Use add_collider_cylinder for that.

Parameters:
  • stage – The Usd.Stage to add cylinder.

  • path – The desired cylinder path.

  • radius – The radius of the cylinder.

  • height – The height of the cylinder.

  • axis – The axis of the cylinder.

  • position – The position where the cylinder should be placed in stage.

  • orientation – The cylinder orientation.

  • color – The color of the mesh.

  • density – The density of the rigid body.

  • lin_velocity – The initial linear velocity of the rigid body.

  • ang_velocity – The initial angular velocity of the rigid body.

ovphysx.utils.shapes.add_rigid_sphere(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
radius: float = 1.0,
position: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
orientation: pxr.Gf.Quatf = Gf.Quatf(1.0),
color: pxr.Gf.Vec3f = Gf.Vec3f(1.0),
density: float = 1.0,
lin_velocity: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
ang_velocity: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
) → pxr.Usd.Prim#

Add UsdGeom.Sphere to the stage and add physics rigid body and collider API to it.

A density of 0.0 still applies UsdPhysics.RigidBodyAPI and UsdPhysics.MassAPI; it is not a request for a static collider. Use add_collider_sphere for that.

Parameters:
  • stage – The Usd.Stage to add sphere.

  • path – The desired sphere path.

  • radius – The radius of the sphere.

  • position – The position where the sphere should be placed in stage.

  • orientation – The sphere orientation.

  • color – The color of the mesh.

  • density – The density of the rigid body.

  • lin_velocity – The initial linear velocity of the rigid body.

  • ang_velocity – The initial angular velocity of the rigid body.

ovphysx.utils.shapes.add_rigid_xform(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
position: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
orientation: pxr.Gf.Quatf = Gf.Quatf(1.0),
scale: pxr.Gf.Vec3f = Gf.Vec3f(1.0),
) → pxr.Usd.Prim#

Add xform to the stage with given transformation and add rigid body API to it.

Parameters:
  • stage – The Usd.Stage to add the xform.

  • path – The desired xform path.

  • position – The position where the xform should be placed in stage.

  • orientation – The xform orientation.

  • scale – The xform scale.

ovphysx.utils.shapes.add_sphere(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
radius: float = 1.0,
position: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
orientation: pxr.Gf.Quatf = Gf.Quatf(1.0),
color: pxr.Gf.Vec3f = Gf.Vec3f(1.0),
) → pxr.Usd.Prim#

Add UsdGeom.Sphere to the stage.

Parameters:
  • stage – The Usd.Stage to add sphere.

  • path – The desired sphere path.

  • radius – The radius of the sphere.

  • position – The position where the sphere should be placed in stage.

  • orientation – The sphere orientation.

  • color – The color of the mesh.

ovphysx.utils.shapes.add_xform(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
position: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
orientation: pxr.Gf.Quatf = Gf.Quatf(1.0),
scale: pxr.Gf.Vec3f = Gf.Vec3f(1.0),
) → pxr.Usd.Prim#

Add xform to the stage with given transformation.

Parameters:
  • stage – The Usd.Stage to add the xform.

  • path – The desired xform path.

  • position – The position where the xform should be placed in stage.

  • orientation – The xform orientation.

  • scale – The xform scale.

Ground and quad planes#

Ground planes and sized quad planes.

A UsdPhysics.Plane is infinite and renders as nothing, so a usable ground plane is two prims: a mesh for the viewport and a collision prim beside it. add_ground_plane() authors that pair under one Xform; add_quad_plane() and add_cube_ground_plane() instead give the collider the finite extent of the geometry itself, which is what a scene needs when a body must be able to fall off the edge.

ovphysx.utils.planes.add_cube_ground_plane(
stage: pxr.Usd.Stage,
cube_path: str | pxr.Sdf.Path,
axis: str,
size: float,
position: pxr.Gf.Vec3f | pxr.Gf.Vec3d,
color: pxr.Gf.Vec3f,
)#

Add UsdGeom.Cube to the stage to act as a sized plane with thickness. The cube is scaled by a vector Gf.Vec3f(0.01, 1.0, 1.0) depending on the up Axis

size is the cube’s full edge length, which is what UsdGeom.Cube’s own size attribute means, so size=2 reaches [-1, 1] across the two lateral axes. On add_ground_plane() and add_quad_plane() size is a half size instead.

Parameters:
  • stage – The Usd.Stage to add path.

  • cube_path – The desired ground plane path.

  • axis – The up axis - “Y”, “Z”

  • size – The edge length of the cube, before the flattening scale.

  • position – The position where the mesh should be placed in stage.

  • color – The color of the mesh.

ovphysx.utils.planes.add_ground_plane(
stage: pxr.Usd.Stage,
plane_path: str | pxr.Sdf.Path,
axis: str,
size: float,
position: pxr.Gf.Vec3f | pxr.Gf.Vec3d,
color: pxr.Gf.Vec3f,
) → str#

Add ground plane to the stage. Note that it will add a mesh for rendering purpose and UsdPhysics.Plane for collision purpose.

Parameters:
  • stage – The Usd.Stage to add path.

  • plane_path – The desired ground plane path.

  • axis – The up axis - “Y”, “Z”

  • size – The half size of the mesh.

  • position – The position where the mesh should be placed in stage.

  • color – The color of the mesh.

ovphysx.utils.planes.add_plane_collider(
stage: pxr.Usd.Stage,
prim_path: str | pxr.Sdf.Path,
up_axis: str,
)#

Define a guide-purpose UsdGeom.Plane and make it a collider.

An occupied path raises ValueError and is not modified.

Parameters:
  • stage – The Usd.Stage to add the plane.

  • prim_path – The desired plane path.

  • up_axis – The plane’s up axis.

ovphysx.utils.planes.add_quad_plane(
stage: pxr.Usd.Stage,
quad_path: str | pxr.Sdf.Path,
axis: str,
size: float,
position: pxr.Gf.Vec3f | pxr.Gf.Vec3d,
color: pxr.Gf.Vec3f,
)#

Add quad mesh to the stage to act as a sized plane.

Parameters:
  • stage – The Usd.Stage to add path.

  • quad_path – The desired ground plane path.

  • axis – The up axis - “Y”, “Z”

  • size – The half size of the mesh.

  • position – The position where the mesh should be placed in stage.

  • color – The color of the mesh.

Joints#

Joint creation between two prims, or between a prim and the world.

create_joint() computes the two local frames from the bodies’ current world poses, so the joint holds them where they already are; add_joint_fixed() takes those frames from the caller instead. Passing one body anchors the joint to the world.

The PhysX joint types are codeless, so they are defined by type name. They derive from UsdPhysicsJoint, which stock usd-core does bind, so they are then reached through that typed base. Refer to ovphysx.utils.codeless.

ovphysx.utils.joints.add_joint_fixed(
stage: pxr.Usd.Stage,
joint_path: str | pxr.Sdf.Path,
actor0: str | pxr.Sdf.Path,
actor1: str | pxr.Sdf.Path,
local_pos0: pxr.Gf.Vec3f,
local_rot0: pxr.Gf.Quatf,
local_pos1: pxr.Gf.Vec3f,
local_rot1: pxr.Gf.Quatf,
break_force: float,
break_torque: float,
) → pxr.UsdPhysics.FixedJoint#

Add fixed joint to the stage.

Parameters:
  • stage – The Usd.Stage to add the joint.

  • joint_path – The desired joint path.

  • actor0 – The actor0 for the joint.

  • actor1 – The actor1 for the joint.

  • local_pos0 – The joint local position offset from the actor0

  • local_rot0 – The joint local rotation offset from the actor0

  • local_pos1 – The joint local position offset from the actor1

  • local_rot1 – The joint local rotation offset from the actor1

  • break_force – The joint break force.

  • break_torque – The joint break torque.

ovphysx.utils.joints.create_joint(
stage: pxr.Usd.Stage,
joint_type: str,
from_prim: pxr.Usd.Prim,
to_prim: pxr.Usd.Prim,
) → pxr.Usd.Prim#

Create a joint between two prims, with local frames computed from their world poses.

The joint prim is placed under the first writable ancestor of to_prim, so that instanced and prototype prims do not break authoring. Passing only one prim anchors the joint to the world.

Parameters:
  • stage – The Usd.Stage to add the joint.

  • joint_type – One of “Fixed”, “Revolute”, “Prismatic”, “Spherical”, “Distance”, “Gear”, “RackAndPinion”; anything else creates a D6 joint with all axes locked.

  • from_prim – The body0 prim, or None.

  • to_prim – The body1 prim.

ovphysx.utils.joints.create_joints(
stage: pxr.Usd.Stage,
joint_type: str,
paths: List[str | pxr.Sdf.Path],
join_to_parent: bool = False,
) → List[pxr.Usd.Prim]#

Create one joint per path, optionally anchoring each to its parent prim.

Parameters:
  • stage – The Usd.Stage to add the joints.

  • joint_type – The joint type, see create_joint.

  • paths – The body1 prim paths.

  • join_to_parent – Whether to use each prim’s parent as body0.

Physics materials#

Physics materials and their binding to prims.

A physics material is a UsdShade.Material carrying UsdPhysics.MaterialAPI, bound to a collider through the physics purpose of UsdShade.MaterialBindingAPI so that it composes independently of any render material on the same prim. Only the friction, restitution and density values the caller supplies are authored; the rest keep their schema fallback.

ovphysx.utils.materials.add_physics_material_to_prim(
stage: pxr.Usd.Stage,
prim: pxr.Usd.Prim,
material_path: str | pxr.Sdf.Path,
)#

Bind physics material to a given prim.

Parameters:
  • stage – The Usd.Stage to add path.

  • prim – The Usd.Prim where material should have the binding to.

  • material_path – The path of the material.

ovphysx.utils.materials.add_rigid_body_material(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
density=None,
static_friction=None,
dynamic_friction=None,
restitution=None,
) → bool#

Define a physics material, authoring only the attributes that were supplied.

Parameters:
  • stage – The Usd.Stage to add the material.

  • path – The desired material path.

  • density – The material density.

  • static_friction – The static friction coefficient.

  • dynamic_friction – The dynamic friction coefficient.

  • restitution – The restitution coefficient.

ovphysx.utils.materials.ensure_material_on_path(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
) → bool#

Define a UsdShade.Material at path if nothing incompatible is already there.

Parameters:
  • stage – The Usd.Stage to add the material.

  • path – The desired material path.

Collision filtering#

Collision filtering: collision groups and filtered pairs.

Two independent mechanisms decide which colliders are allowed to interact. A UsdPhysics.CollisionGroup holds a collection of colliders and a relationship naming the groups it does not collide with, which is the scalable one. A UsdPhysics.FilteredPairsAPI names individual prims on the prim itself, which is the one to reach for when two specific bodies must ignore each other.

ovphysx.utils.filtering.add_collision_group(stage: pxr.Usd.Stage, path: str | pxr.Sdf.Path)#

Define a collision group with an empty filtered-groups relationship.

Parameters:
  • stage – The Usd.Stage to add the group.

  • path – The desired collision group path.

ovphysx.utils.filtering.add_collision_to_collision_group(
stage: pxr.Usd.Stage,
collision_path: str | pxr.Sdf.Path,
collision_group_path: str | pxr.Sdf.Path,
)#

Add collision path to a collision group include rel.

Parameters:
  • stage – The Usd.Stage to add path.

  • collision_path – Collision path to add.

  • collision_group_path – Collision group prim path.

ovphysx.utils.filtering.add_pair_filter(
stage: pxr.Usd.Stage,
paths: List[str | pxr.Sdf.Path],
)#

Make every prim in paths filter collisions against every other one.

Duplicate entries and a mix of str and Sdf.Path spellings of the same prim are tolerated. Paths are compared by value, so no prim is given a filter against itself.

Parameters:
  • stage – The Usd.Stage holding the prims.

  • paths – The prim paths to filter against each other.

ovphysx.utils.filtering.is_in_collision_group(
stage: pxr.Usd.Stage,
collision_path: str | pxr.Sdf.Path,
collision_group_path: str | pxr.Sdf.Path,
) → bool#

Checks if a collision path belongs to a collision group include rel.

Parameters:
  • stage – The Usd.Stage to add path.

  • collision_path – Collision path to add.

  • collision_group_path – Collision group prim path.

ovphysx.utils.filtering.remove_collision_from_collision_group(
stage: pxr.Usd.Stage,
collision_path: str | pxr.Sdf.Path,
collision_group_path: str | pxr.Sdf.Path,
)#

Remove collision path to a collision group include rel.

Parameters:
  • stage – The Usd.Stage to add path.

  • collision_path – Collision path to add.

  • collision_group_path – Collision group prim path.

ovphysx.utils.filtering.remove_pair_filter(
stage: pxr.Usd.Stage,
paths: List[str | pxr.Sdf.Path],
)#

Undo add_pair_filter for the given paths.

The UsdPhysics.FilteredPairsAPI is removed, and the physics:filteredPairs relationship with it, so a later add_pair_filter starts from no targets.

Parameters:
  • stage – The Usd.Stage holding the prims.

  • paths – The prim paths to stop filtering.

Rigid bodies and colliders on existing prims#

Applying physics to prims that already exist.

Where shapes builds a body and its collider together, the helpers here take a prim a stage already has and give it – or take from it – mass, a force, a physics scene, or a whole API set. The set* and remove* family is the core of that: it applies and strips the collider and rigid-body API sets, and an Xformable is given colliders across its whole subtree and stripped of them the same way.

The two halves are inverses over the API schemas, and only partly over the properties authored under them. Usd.Prim.RemoveAPI and remove_api() drop the apiSchemas entry alone, so remove_physics() and the rigid-body helpers built on it leave every property in place: a prim that has to come out clean needs remove_api_schema_properties() as well – and create_api_schema_property_cache() first, if those values have to survive the round trip. remove_collider() is the deliberate exception, and the helpers that call it inherit what it does: it takes the mesh approximation and cooked-data APIs’ properties with the APIs, since those APIs are mutually exclusive and their properties would otherwise orphan onto a prim re-approximated another way. The collision APIs set_collider() re-applies keep theirs, so a re-approximated collider keeps its contact tuning.

How schemas are reached here#

PhysX APIs are applied by identifier and their properties authored by name, because the PhysX schemas are codeless. Refer to ovphysx.utils.codeless. Core UsdPhysics schemas still use their typed bindings, which are part of stock usd-core.

ovphysx.utils.authoring.add_density(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
value: float,
) → pxr.UsdPhysics.MassAPI#

Add density to given prim. Note that his will apply MassAPI on the prim.

Parameters:
  • stage – The Usd.Stage to add path.

  • path – The desired path to create.

  • value – The desired density.

ovphysx.utils.authoring.add_force_torque(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
force: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
torque: pxr.Gf.Vec3f = Gf.Vec3f(0.0),
mode: str = 'acceleration',
is_enabled: bool = True,
is_world_space: bool = False,
) → pxr.Usd.Prim#

Add force/torque to given prim. Note that his will apply PhysxForceAPI on the prim.

Parameters:
  • stage – The Usd.Stage to add path.

  • path – The desired path to create.

  • force – The desired force.

  • torque – The desired torque.

  • mode – The force/torque mode, “force” or “acceleration”.

  • is_enabled – Bool defining whether force is enabled or not.

  • is_world_space – Bool defining whether force is applied in world space or body local space.

Returns:

The prim the API was applied to.

ovphysx.utils.authoring.add_mass(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
mass: float = 1.0,
) → pxr.UsdPhysics.MassAPI#

Add mass to given prim. Note that his will apply MassAPI on the prim.

Parameters:
  • stage – The Usd.Stage to add path.

  • path – The desired path to create.

  • mass – The desired mass.

ovphysx.utils.authoring.add_physics_scene(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
) → List#

Define a UsdPhysics.Scene, unless a prim already exists at path.

Parameters:
  • stage – The Usd.Stage to add the scene.

  • path – The desired scene path.

Returns:

A list holding the created path, or an empty list if nothing was created.

ovphysx.utils.authoring.clear_local_space_velocities(prim: pxr.Usd.Prim)#

Undo set_local_space_velocities, returning the prim to world-space velocities.

Parameters:

prim – The rigid body prim.

ovphysx.utils.authoring.remove_collider(prim: pxr.Usd.Prim)#

Remove the collision API set from a prim, including mesh approximation and cooked data.

The mesh approximation APIs are stripped from instanceable prims as well as meshes, mirroring set_collider. Every approximation API set_collider can apply is removed, the PhysX-only sdf and sphereFill ones included.

The approximation and cooked-data APIs’ authored properties are removed with the APIs, so nothing is left orphaned.

PhysicsCollisionAPI, PhysxCollisionAPI and PhysicsMeshCollisionAPI keep their properties – physxCollision:contactOffset and physxCollision:restOffset above all – because every set_collider() call re-applies those APIs, so a re-approximated collider keeps its contact tuning. A caller who wants those gone too calls remove_api_schema_properties() for them, as the example in create_api_schema_property_cache() does.

Parameters:

prim – The prim to strip.

ovphysx.utils.authoring.remove_collider_subtree(prim: pxr.Usd.Prim)#

Remove the collision API set from every gprim and instanceable prim in a subtree.

Instanceable prims are visited as well as gprims, mirroring set_collider_subtree; an instanceable prim is not a gprim.

Parameters:

prim – The subtree root.

ovphysx.utils.authoring.remove_physics(prim: pxr.Usd.Prim)#

Remove the rigid body API set from a prim.

Parameters:

prim – The prim to strip.

ovphysx.utils.authoring.remove_rigid_body(prim: pxr.Usd.Prim)#

Undo set_rigid_body, following the same Xformable subtree rule.

Parameters:

prim – The prim to strip.

ovphysx.utils.authoring.remove_rigid_body_subtree(prim: pxr.Usd.Prim)#

Remove the rigid body API from a prim and the collision APIs from its subtree.

Parameters:

prim – The subtree root.

ovphysx.utils.authoring.remove_static_collider(prim: pxr.Usd.Prim)#

Undo set_static_collider.

Parameters:

prim – The subtree root.

ovphysx.utils.authoring.set_collider(
prim: pxr.Usd.Prim,
approximation_shape=UsdPhysics.Tokens.none,
)#

Apply the collision API set to a prim, choosing the mesh approximation APIs to match.

A mesh that is part of a rigid body cannot use the triangle-mesh approximation, so a none request on such a mesh is upgraded to convexHull with a warning.

A prim that is already a collider is left untouched with a warning. A prim whose omni:no_collision attribute is true is left untouched. An authored false value does not opt out of collision.

Parameters:
  • prim – The prim to make a collider.

  • approximation_shape – The mesh approximation token, one of "none", "convexHull", "convexDecomposition", "meshSimplification", "boundingCube", "boundingSphere", "sphereFill" or "sdf". The first six are the UsdPhysics.Tokens values; the last two are PhysX-only and are declared here as ovphysx.utils.TOKEN_SPHERE_FILL and ovphysx.utils.TOKEN_SDF.

ovphysx.utils.authoring.set_collider_subtree(
prim: pxr.Usd.Prim,
approximation_shape=UsdPhysics.Tokens.none,
)#

Apply the collision API set to every gprim and instanceable prim in a subtree.

Parameters:
  • prim – The subtree root.

  • approximation_shape – The mesh approximation token, see set_collider.

ovphysx.utils.authoring.set_local_space_velocities(prim: pxr.Usd.Prim, value: bool)#

Choose whether a rigid body’s authored velocities are read in its own frame.

With this enabled the velocity and angularVelocity attributes are interpreted in the body’s local frame instead of world space: the linear velocity is scaled by the body’s world scale along its local axes and then rotated into world space, and the angular velocity is rotated without being scaled. This holds at load and for supported later edits.

On a PointInstancer prototype this also governs the instancer’s velocities and angularVelocities arrays. Each instance’s frame is its own world pose – the instancer’s transform composed with the instance’s orientations entry and the prototype’s local rotation – read as it is when the value is applied, so an edit that lands after the instance has turned is interpreted in the turned frame.

After the scene’s first DirectGPU step, live ovstage velocity edits do not update dynamic (non-kinematic) bodies; use world-space linearVelocity and angularVelocity session writes instead. Session angularVelocity is in rad/s, while USD physics:angularVelocity is in deg/s; convert by pi / 180 as well as rotating the vector into world space.

Parameters:
  • prim – The rigid body prim.

  • value – True to interpret velocities in body local space.

ovphysx.utils.authoring.set_physics(prim: pxr.Usd.Prim, kinematic: bool)#

Apply the rigid body API set to a prim.

If the core rigid-body API is already present, this function completes the API set, enables the body, and updates its kinematic state.

Parameters:
  • prim – The prim to make a rigid body.

  • kinematic – Whether the body is kinematic.

ovphysx.utils.authoring.set_physics_scene_asyncsimrender(
scene_prim: pxr.Usd.Prim,
val: bool = True,
)#

Switch a physics scene between asynchronous and synchronous update, unless it is disabled.

Parameters:
  • scene_prim – The UsdPhysics.Scene prim.

  • val – True for asynchronous, False for synchronous.

ovphysx.utils.authoring.set_rigid_body(
prim: pxr.Usd.Prim,
approximation_shape,
kinematic: bool,
)#

Make a prim a rigid body and give it colliders.

An Xformable gets colliders across its whole subtree, matching how a rigid-body hierarchy is normally authored; anything else is treated as a single collider.

Parameters:
  • prim – The prim to make a rigid body.

  • approximation_shape – The mesh approximation token, see set_collider.

  • kinematic – Whether the body is kinematic.

ovphysx.utils.authoring.set_static_collider(
prim: pxr.Usd.Prim,
approximation_shape=UsdPhysics.Tokens.none,
)#

Give a subtree colliders without making it a rigid body.

Parameters:
  • prim – The subtree root.

  • approximation_shape – The mesh approximation token, see set_collider.

Stage paths#

Stage path uniquification.

Authoring a prim at a path another prim already holds silently redefines that prim, so every helper that defines geometry resolves its path through here first. Both helpers only compute a name – neither touches the stage beyond asking what is already at a path.

ovphysx.utils.paths.get_stage_next_free_path(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
prepend_default_prim: bool,
) → str#

Gets valid path in stage, if the path already exists it will append number.

Parameters:
  • stage – The Usd.Stage to add path.

  • path – The desired path to create.

  • prepend_default_prim – Whether prepend default prim path name.

Transforms#

Transform and xform-op helpers.

The physics runtime expects a translate-orient-scale xform op stack, and authoring one correctly by hand is fiddly: an op may already exist at a different precision, and resetXformStack has to survive a rewrite. These helpers encapsulate that.

ovphysx.utils.transform.copy_transform_as_scale_orient_translate(
src: pxr.Usd.Prim | pxr.UsdGeom.Xformable,
dst: pxr.Usd.Prim | pxr.UsdGeom.Xformable,
)#

Copies the local transforms from one Xformable to another as a default scale->orient->translate stack.

Note that:
  • Any skew in the src transform will be lost.

  • A resetXformStack is preserved, but not the XformOps that are ignored due to the reset.

  • The transform attribute precision of added XformOps is set to UsdGeom.XformOp.PrecisionFloat.

  • Obsolete xformOp: namespace attributes in dst are not removed (and cannot be for layers)

Parameters:
  • src – The source prim or Xformable.

  • dst – The destination prim or Xformable.

ovphysx.utils.transform.get_aligned_body_transform(stage, cache, joint, body0base)#

Compute the transform that aligns one joint body onto the other.

Parameters:
  • stage – The Usd.Stage holding the bodies.

  • cache – A UsdGeom.XformCache used for the world transforms.

  • joint – The UsdPhysics.Joint to read.

  • body0base – True to treat body0 as the fixed base, False for body1.

ovphysx.utils.transform.get_axis_aligned_vector(axis, len)#

Build an axis-aligned vector of the given length.

Parameters:
  • axis – The axis name - “X”, “Y” or “Z”.

  • len – The signed length along that axis.

ovphysx.utils.transform.get_basis(up_axis)#

Get the (up, forward, right) basis vectors for a stage’s up axis.

Parameters:

up_axis – The stage up axis - “Y” selects a Y-up basis, anything else selects a Z-up basis.

ovphysx.utils.transform.get_forward_vector(up_axis)#

Get the forward vector for a stage’s up axis.

Parameters:

up_axis – The stage up axis - “Y” or “Z”.

ovphysx.utils.transform.get_translation(prim: pxr.Usd.Prim) → pxr.Gf.Vec3f | pxr.Gf.Vec3d#

Return the translate xform op value from the given prim.

Parameters:

prim – The Usd.Prim to check.

ovphysx.utils.transform.get_unit_scale_factor(stage)#

Get the stage’s units-per-meter scale factor.

Non-positive or non-finite metersPerUnit values log a warning and use 1.0 meter per unit, without changing the stage metadata.

Parameters:

stage – The Usd.Stage to query.

ovphysx.utils.transform.get_world_position(stage, path)#

Get the world-space center of a prim’s axis-aligned world bound.

Parameters:
  • stage – The Usd.Stage to query.

  • path – The path of the imageable prim.

ovphysx.utils.transform.set_or_add_orient_op(
xformable: pxr.UsdGeom.Xformable,
orient: pxr.Gf.Quatf | pxr.Gf.Quatd | pxr.Gf.Quath,
) → pxr.UsdGeom.XformOp | None#

Sets or adds the orient XformOp on the input Xformable to provided orient value.

Note that:
  • The precision of an added attribute is UsdGeom.XformOp.PrecisionFloat.

Parameters:
  • xformable – The Xformable to modify.

  • orient – The orient quaternion

Returns:

The set or added XformOp, or None if the prim is not an Xformable. Its scale and translate siblings answer False for that case rather than None.

ovphysx.utils.transform.set_or_add_scale_op(
xformable: pxr.UsdGeom.Xformable,
scale: pxr.Gf.Vec3f | pxr.Gf.Vec3d | pxr.Gf.Vec3h,
) → pxr.UsdGeom.XformOp | Literal[False]#

Sets or adds the scale XformOp on the input Xformable to provided scale value.

Note that:
  • The precision of an added attribute is UsdGeom.XformOp.PrecisionFloat.

Parameters:
  • xformable – The Xformable to modify.

  • scale – The scale vector

Returns:

The set or added XformOp, or False if the prim is not an Xformable.

ovphysx.utils.transform.set_or_add_scale_orient_translate(
xformable: pxr.UsdGeom.Xformable,
scale: pxr.Gf.Vec3f | pxr.Gf.Vec3d | pxr.Gf.Vec3h,
orient: pxr.Gf.Quatf | pxr.Gf.Quatd | pxr.Gf.Quath,
translate: pxr.Gf.Vec3f | pxr.Gf.Vec3d | pxr.Gf.Vec3h,
) → List[pxr.UsdGeom.XformOp] | Literal[False]#

Sets or adds scale, orient, and translate XformOps of xformable.

Note that:
  • The precision of created attributes is UsdGeom.XformOp.PrecisionFloat.

Parameters:
  • xformable – The Xformable to modify.

  • scale – The scale vector

  • orient – The orientation quaternion

  • translate – The translation vector

Returns:

List of set and created xform ops that will be [translate, orient, scale], or False if the prim is not an Xformable.

ovphysx.utils.transform.set_or_add_translate_op(
xformable: pxr.UsdGeom.Xformable,
translate: pxr.Gf.Vec3f | pxr.Gf.Vec3d | pxr.Gf.Vec3h,
) → pxr.UsdGeom.XformOp | Literal[False]#

Sets or adds the translate XformOp on the input Xformable to provided translate value.

Note that:
  • The precision of an added attribute is UsdGeom.XformOp.PrecisionFloat.

Parameters:
  • xformable – The Xformable to modify.

  • translate – The translate vector

Returns:

The set or added XformOp, or False if the prim is not an Xformable.

ovphysx.utils.transform.setup_transform_as_scale_orient_translate(
xformable: pxr.Usd.Prim | pxr.UsdGeom.Xformable,
)#

Changes the local transform (ops) to the physics default scale->orient->translate stack.

Note that:
  • Any skew in the transform will be lost.

  • A resetXformStack is preserved, but not the XformOps that are ignored due to the reset.

  • The transform attribute precision is set to UsdGeom.XformOp.PrecisionFloat.

  • Obsolete xformOp: namespace attributes are not removed (and cannot be for layers)

Parameters:

xformable – The prim or Xformable to modify.

Mesh construction and tetrahedral meshes#

Procedural mesh construction and triangle / tetrahedron mesh math.

Two groups of helper live here: constructors that define a UsdGeom.Mesh for a primitive shape, and pure geometry routines over point and index lists that carry no USD state.

create_tetra_voxels yields an empty mesh for a non-positive integer voxel_dim rather than raising.

ovphysx.utils.mesh.calculate_tetra_volume(a, b, c, d)#

Compute the signed volume of a tetrahedron.

Parameters:
  • a – The four tetrahedron corner points.

  • b – The four tetrahedron corner points.

  • c – The four tetrahedron corner points.

  • d – The four tetrahedron corner points.

ovphysx.utils.mesh.compute_bounding_box_diagonal(points) → float#

Gets diagonal length of given point bounds.

Parameters:

points – The input points. Any iterable of indexable three-component points, e.g. Gf.Vec3f, tuples or lists.

Raises:

ValueError – If points is empty.

ovphysx.utils.mesh.convert_tetra_to_triangle_soup(points_in, indices_in)#

Expand every tetrahedron into its four unshared triangles.

Parameters:
  • points_in – The tet mesh points.

  • indices_in – The tet mesh vertex indices, four per tetrahedron.

ovphysx.utils.mesh.create_mesh(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
points: List[pxr.Gf.Vec3f] | List[pxr.Gf.Vec3d],
normals: List[pxr.Gf.Vec3f] | List[pxr.Gf.Vec3d],
indices: List[int],
vertex_counts: List[int],
) → pxr.UsdGeom.Mesh#

Create UsdGeom.Mesh from given points, normals, indices and face counts.

Parameters:
  • stage – The Usd.Stage to add path.

  • path – The desired path to create.

  • points – The input points.

  • normals – The input normals.

  • indices – The indices for faces.

  • vertex_counts – Face counts.

ovphysx.utils.mesh.create_mesh_concave(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
half_size: float,
) → pxr.UsdGeom.Mesh#

Create UsdGeom.Mesh that represents a concave mesh.

Parameters:
  • stage – The Usd.Stage to add path.

  • path – The desired path to create.

  • half_size – The half size of the mesh.

ovphysx.utils.mesh.create_mesh_cone(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
height: float,
radius: float,
tesselation: int = 32,
) → pxr.UsdGeom.Mesh#

Create UsdGeom.Mesh that represents a cone mesh.

Parameters:
  • stage – The Usd.Stage to add path.

  • path – The desired path to create.

  • height – The finite, positive height of the cone.

  • radius – The finite, non-negative radius of the cone.

  • tesselation – The number of cone segments, at least three.

Raises:

ValueError – If dimensions are invalid or tesselation is below three. Validation occurs before the stage is modified.

ovphysx.utils.mesh.create_mesh_cube(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
half_size: float,
) → pxr.UsdGeom.Mesh#

Create UsdGeom.Mesh that represents a cube mesh.

Parameters:
  • stage – The Usd.Stage to add path.

  • path – The desired path to create.

  • half_size – The half size of the cube.

ovphysx.utils.mesh.create_mesh_cylinder(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
height: float,
radius: float,
tesselation: int = 32,
) → pxr.UsdGeom.Mesh#

Create UsdGeom.Mesh that represents a cylinder mesh.

Parameters:
  • stage – The Usd.Stage to add path.

  • path – The desired path to create.

  • height – The height of the cylinder.

  • radius – The radius of the cylinder.

  • tesselation – The tesselation of the cylinder mesh.

ovphysx.utils.mesh.create_mesh_square_axis(
stage: pxr.Usd.Stage,
path: str | pxr.Sdf.Path,
axis: str,
half_size: float,
) → pxr.UsdGeom.Mesh#

Create UsdGeom.Mesh that represents a square.

Parameters:
  • stage – The Usd.Stage to add path.

  • path – The desired path to create.

  • axis – The up axis “Y”, “Z”.

  • half_size – The half size of the square.

ovphysx.utils.mesh.create_tetra_voxel_box(voxel_dim)#

Build a unit-cube tetrahedral mesh centered on the origin.

A non-positive integer grid resolution yields an empty mesh.

Parameters:

voxel_dim – The voxel grid resolution.

ovphysx.utils.mesh.create_tetra_voxel_sphere(voxel_dim)#

Build a unit-diameter sphere tetrahedral mesh centered on the origin.

A non-positive integer grid resolution yields an empty mesh.

Parameters:

voxel_dim – The voxel grid resolution.

ovphysx.utils.mesh.create_tetra_voxels(voxel_dim, occupancy_filter_func)#

Build a tetrahedral mesh from an occupancy-filtered voxel grid.

Every occupied voxel is split into the five tetrahedra of cube_tetrahedra. Alternate cubes are mirrored per axis, and a cube mirrored an odd number of times has its tetrahedra re-wound, so neighbouring cubes share faces.

Parameters:
  • voxel_dim – The grid resolution, used for all three axes. A non-positive integer yields an empty mesh.

  • occupancy_filter_func – Called as (x, y, z, dimx, dimy, dimz); returns True for an occupied voxel.

ovphysx.utils.mesh.create_triangle_mesh_cube(dim: int)#

Build the surface triangle mesh of a voxelized unit cube.

A non-positive integer grid resolution yields an empty mesh.

Parameters:

dim – The voxel grid resolution.

ovphysx.utils.mesh.create_triangle_mesh_square(dimx: int, dimy: int, scale: float = 1.0)#

Creates points and vertex data for a regular-grid flat triangle mesh square.

A non-positive integer grid dimension yields an empty mesh.

Parameters:
  • dimx – Mesh-vertex resolution in X

  • dimy – Mesh-vertex resolution in Y

  • scale – Uniform scale applied to vertices

Returns:

The vertex and index data

Return type:

points, indices

ovphysx.utils.mesh.cube_tetrahedra()#

Return the five-tetrahedron decomposition of a unit cube.

ovphysx.utils.mesh.extract_triangle_surface_from_tetra(tetra_points, tetra_indices)#

Extract the outer surface triangles of a tetrahedral mesh.

Occurrences of each face are counted: a face that appears more than once is interior and is discarded, and the faces appearing exactly once form the surface.

Parameters:
  • tetra_points – The tet mesh points.

  • tetra_indices – The tet mesh vertex indices, four per tetrahedron.

ovphysx.utils.mesh.fixup_tetra_mesh_volumes(points, indices)#

Return tet indices with inverted tetrahedra re-wound to positive volume.

Parameters:
  • points – The tet mesh points.

  • indices – The tet mesh vertex indices, four per tetrahedron.

ovphysx.utils.mesh.triangulate_mesh(mesh: pxr.UsdGeom.Mesh) → List[int]#

Fan-triangulate a mesh’s faces into a flat triangle index list.

Parameters:

mesh – The UsdGeom.Mesh to read.

ovphysx.utils.mesh.verify_tetra_mesh(points, indices)#

Check a tet mesh for index-count, out-of-range and inverted-volume errors.

Problems are logged as warnings; the first one found stops the check. An index below zero is out of range on the same terms as one past the end.

Parameters:
  • points – The tet mesh points.

  • indices – The tet mesh vertex indices, four per tetrahedron.

Particles#

Particle system, particle set and PBD material authoring.

A particle simulation needs a PhysxParticleSystem prim, a set prim carrying PhysxParticleSetAPI that points back at it, and usually a PBD material. The helpers here author all three, plus the optional feature APIs (anisotropy, smoothing, isosurface, diffuse particles) and the sampling API.

Every schema attribute is an optional keyword that defaults to None and is only authored when supplied, so an unset attribute keeps the schema fallback rather than being pinned to a value chosen here.

The PhysX schemas are codeless, so these helpers apply APIs by identifier and author properties by name; add_physx_particle_system() answers with the Usd.Prim it defined. Refer to ovphysx.utils.codeless.

ovphysx.utils.particles.add_pbd_material_viscous(p)#

Applies a viscous-fluid PBD material preset to a material prim.

The surface tension and viscosity presets are in SI, so they are converted to the stage’s units before being authored.

Parameters:

p – The UsdShade.Material prim.

ovphysx.utils.particles.add_pbd_material_water(p)#

Applies a water PBD material preset to a material prim.

The surface tension and viscosity presets are in SI, so they are converted to the stage’s units before being authored.

Parameters:

p – The UsdShade.Material prim.

ovphysx.utils.particles.add_pbd_particle_material(
stage,
path,
friction=None,
particle_friction_scale=None,
damping=None,
viscosity=None,
vorticity_confinement=None,
surface_tension=None,
cohesion=None,
adhesion=None,
particle_adhesion_scale=None,
adhesion_offset_scale=None,
gravity_scale=None,
density=None,
cfl_coefficient=None,
)#

Applies the PhysxPBDMaterialAPI to the prim at path on stage.

Parameters:
  • stage – The stage

  • path – Path to UsdShade.Material to which the material API should be applied to

  • attributes (... schema) – See USD schema for documentation

Returns:

True if the API apply succeeded.

ovphysx.utils.particles.add_physx_diffuse_particles(
stage,
path,
enabled=None,
max_diffuse_particle_multiplier=None,
threshold=None,
lifetime=None,
air_drag=None,
bubble_drag=None,
buoyancy=None,
kinetic_energy_weight=None,
pressure_weight=None,
divergence_weight=None,
collision_decay=None,
use_accurate_velocity=None,
)#

Applies the PhysxDiffuseParticlesAPI to the prim at path on stage.

Parameters:
  • stage – The stage

  • path – Path to the prim to which the diffuse particle API should be applied to

  • attributes (... schema) – See USD schema for documentation

Returns:

True if the API apply succeeded.

ovphysx.utils.particles.add_physx_particle_anisotropy(
stage,
path,
enabled=None,
scale=None,
min=None,
max=None,
)#

Applies the PhysxParticleAnisotropyAPI to the prim at path on stage.

Parameters:
  • stage – The stage

  • path – Path to the prim to which the anisotropy API should be applied to

  • attributes (... schema) – See USD schema for documentation

Returns:

True if the API apply succeeded.

ovphysx.utils.particles.add_physx_particle_isosurface(
stage,
path,
enabled=None,
max_vertices=None,
max_triangles=None,
max_subgrids=None,
grid_spacing=None,
surface_distance=None,
grid_filtering_passes=None,
grid_smoothing_radius=None,
num_mesh_smoothing_passes=None,
num_mesh_normal_smoothing_passes=None,
)#

Applies the PhysxParticleIsosurfaceAPI to the prim at path on stage.

Parameters:
  • stage – The stage

  • path – Path to the prim to which the isosurface API should be applied to

  • attributes (... schema) – See USD schema for documentation

Returns:

True if the API apply succeeded.

ovphysx.utils.particles.add_physx_particle_smoothing(stage, path, enabled=None, strength=None)#

Applies the PhysxParticleSmoothingAPI to the prim at path on stage.

Parameters:
  • stage – The stage

  • path – Path to the prim to which the smoothing API should be applied to

  • attributes (... schema) – See USD schema for documentation

Returns:

True if the API apply succeeded.

ovphysx.utils.particles.add_physx_particle_system(
stage,
particle_system_path,
particle_system_enabled=None,
simulation_owner=None,
contact_offset=None,
rest_offset=None,
particle_contact_offset=None,
solid_rest_offset=None,
fluid_rest_offset=None,
enable_ccd=None,
solver_position_iterations=None,
max_depenetration_velocity=None,
wind=None,
max_neighborhood=None,
neighborhood_scale=None,
max_velocity=None,
global_self_collision_enabled=None,
non_particle_collision_enabled=None,
) → pxr.Usd.Prim | None#

Creates a PhysxParticleSystem prim at particle_system_path on stage.

Parameters:
  • stage – The stage

  • particle_system_path – Path where the system should be created at

  • attributes (... schema) – See USD schema for documentation

An occupied path is rejected with a ValueError rather than the prim that is already there being retyped.

The concrete codeless prim type must be registered before this function mutates the stage.

Returns:

The particle system Usd.Prim, or None if the prim could not be defined.

Raises:

CodelessSchemaError – If PhysxParticleSystem is not registered.

ovphysx.utils.particles.add_physx_particleset_pointinstancer(
stage,
path: str | pxr.Sdf.Path,
positions,
velocities,
particle_system_path,
self_collision,
fluid,
particle_group,
particle_mass,
density,
num_prototypes: int = 1,
prototype_indices: list | None = None,
) → pxr.Usd.Prim#

Creates a particle set based on a UsdGeom.PointInstancer at path on stage.

Parameters:
  • stage – The stage

  • path – Path where the UsdGeom.PointInstancer particle set should be created

  • positions – List of particle positions

  • velocities – List of particle velocities

  • particle_system_path – Path to particle system that simulates the set

  • self_collision – Enable particle-particle collision in the set

  • fluid – Simulate the particle set as fluid

  • particle_group – The particle group, see schema API doc

  • particle_mass – The per-particle mass - total mass of set is num particles * particle_mass

  • density – The density of the particles - is used to compute particle (set) mass if no mass provided

  • num_prototypes – The number of render prototypes to create (children of point instancer)

  • prototype_indices – The prototype indices for the particles (same length as positions). Will default to 0 for all if not provided.

An occupied path is rejected with a ValueError rather than the prim that is already there being retyped.

Returns:

The created UsdGeom.PointInstancer prim

ovphysx.utils.particles.add_physx_particleset_points(
stage,
path,
positions_list,
velocities_list,
widths_list,
particle_system_path,
self_collision,
fluid,
particle_group,
particle_mass,
density,
) → pxr.UsdGeom.Points#

Creates a particle set based on a UsdGeom.Points at path on stage.

Parameters:
  • stage – The stage

  • path – Path where the UsdGeom.Points particle set should be created

  • positions_list – List of particle positions

  • velocities_list – List of particle velocities

  • widths_list – List of particle widths

  • particle_system_path – Path to particle system that simulates the set

  • self_collision – Enable particle-particle collision in the set

  • fluid – Simulate the particle set as fluid

  • particle_group – The particle group, see schema API doc

  • particle_mass – The per-particle mass - total mass of set is num particles * particle_mass

  • density – The density of the particles - is used to compute particle (set) mass if no mass provided

An occupied path is rejected with a ValueError rather than the prim that is already there being retyped.

Returns:

The UsdGeom.Points

ovphysx.utils.particles.configure_particle_set(
particle_set_prim,
particle_system_path,
self_collision,
fluid,
particle_group,
mass=0.0,
density=0.0,
)#

Applies the particle set and mass APIs that turn a points or instancer prim into particles.

Parameters:
  • particle_set_prim – The UsdGeom.Points or UsdGeom.PointInstancer prim.

  • particle_system_path – Path to the particle system that simulates the set.

  • self_collision – Enable particle-particle collision in the set.

  • fluid – Simulate the particle set as fluid.

  • particle_group – The particle group, see schema API doc.

  • mass – The total mass of the set.

  • density – The density used when no mass is provided.

ovphysx.utils.particles.create_particles_grid(
lower,
particle_spacing,
dim_x,
dim_y,
dim_z,
uniform_particle_velocity=Gf.Vec3f(0.0),
) → Tuple[List[pxr.Gf.Vec3f], List[pxr.Gf.Vec3f]]#

Builds a regular grid of particle positions and a matching velocity list.

Parameters:
  • lower – The grid’s minimum corner.

  • particle_spacing – The distance between adjacent particles.

  • dim_x – Particle count along X.

  • dim_y – Particle count along Y.

  • dim_z – Particle count along Z.

  • uniform_particle_velocity – The velocity given to every particle.

Returns:

A (positions, velocities) tuple.

ovphysx.utils.particles.poisson_sample_mesh(stage: pxr.Usd.Stage, prim_path: pxr.Sdf.Path)#

Marks a mesh for volume particle sampling, creating a particle system if the stage has none.

Only authors the sampling request; the runtime performs the sampling when the stage is simulated.

The stage’s first particle system is reused wherever it sits. Creating one defines /World and makes it the stage default prim when the stage has none.

Parameters:
  • stage – The stage.

  • prim_path – Path to the mesh to sample.

Returns:

The path of the particle system that will sample the mesh, or an empty Sdf.Path if no particle system could be obtained.

A stage that has no particle system and whose default particle system path is already held by a prim of another type gets the empty path too, rather than that prim being written over.

Deformables#

Volume and surface deformable body authoring.

A deformable body is spread across several prims and API schemas, and getting the combination wrong fails quietly at parse time rather than loudly at authoring time. These helpers validate the prim type up front, apply the schema set in the order the parser expects, and author the rest-shape attributes.

Two shapes are supported. The set_physics_*_deformable_body pair configures a single prim that is both the simulation and the collision geometry. The create_auto_*_deformable_hierarchy pair builds the multi-prim layout instead, where a root prim carries the body API, a cooking source mesh drives generation of the simulation and collision meshes, and any remaining point-based geometry in the subtree becomes skinned visual geometry with a bind pose.

The deformable schemas are multiple-apply and partly codeless, so they are reached by type name through Usd.Prim.ApplyAPI and by property path rather than through generated Python classes.

The bind-pose writes in the two create_auto_* helpers are the one exception to routing property access through codeless. They use Usd.Prim.CreateAttribute directly, so that a prim whose OmniPhysicsDeformablePoseAPI application USD refuses does not abort the pass over the rest of the subtree; codeless.set_attr would raise there. REQ-PYTHON-UTILS-001, “Where the deformable pose attributes stay raw”, records the reasoning.

ovphysx.utils.deformable.add_auto_deformable_mesh_simplification(
stage,
prim_path: pxr.Sdf.Path,
) → bool#
Add a simplification collision mesh on a prim with PhysxAutoDeformableBodyAPI, and setup the deformable

body correspondingly.

Parameters:
  • stage – The stage

  • prim_path – Path to UsdGeom.Scope/UsdGeom.Xform to which the PhysxAutoDeformableBodyAPI is applied to.

Returns:

True / False that indicates success of schema application

ovphysx.utils.deformable.add_deformable_material(
stage: pxr.Usd.Stage,
path,
density=None,
static_friction=None,
dynamic_friction=None,
youngs_modulus=None,
poissons_ratio=None,
)#

Applies the UsdPhysics.DeformableMaterialAPI to the prim at path on stage.

Parameters:
  • stage – The stage

  • path – Path to UsdShade.Material to which the material API should be applied to.

  • attributes (... schema) – See USD schema for documentation

Returns:

True if the API apply succeeded.

ovphysx.utils.deformable.add_surface_deformable_material(
stage: pxr.Usd.Stage,
path,
density=None,
static_friction=None,
dynamic_friction=None,
youngs_modulus=None,
poissons_ratio=None,
surface_thickness=None,
surface_stretch_stiffness=None,
surface_shear_stiffness=None,
surface_bend_stiffness=None,
)#

Applies the UsdPhysics.SurfaceDeformableMaterialAPI to the prim at path on stage.

Parameters:
  • stage – The stage

  • path – Path to UsdShade.Material to which the material API should be applied to.

  • attributes (... schema) – See USD schema for documentation

Returns:

True if the API apply succeeded.

ovphysx.utils.deformable.create_auto_surface_deformable_hierarchy(
stage: pxr.Usd.Stage,
root_prim_path: str | pxr.Sdf.Path,
simulation_mesh_path: str | pxr.Sdf.Path,
cooking_src_mesh_path: str | pxr.Sdf.Path,
cooking_src_simplification_enabled: bool,
set_visibility_with_guide_purpose: bool = False,
) → bool#

Creates a surface deformable body from a stage hierachy and adds necessary prims and APIs. For single prim deformable bodies, use set_physics_surface_deformable_body on a UsdGeom.Mesh.

Parameters:
  • stage – The stage

  • root_prim_path – Path to valid a UsdGeom.Imageable which cannot be a UsdGeom.Gprim. The UsdPhysics.DeformableBodyAPI is applied to this prim.

  • simulation_mesh_path – Path to where simulation mesh should be created or a valid UsdGeom.Mesh.

  • cooking_src_mesh_path – Path to valid UsdGeom.Mesh that is used in cooking to generate the simulation mesh. May be outside of root_prim_path sub-hierarchy.

  • cooking_src_simplification_enabled – If True, PhysxAutoDeformableMeshSimplificationAPI is applied.

  • set_visibility_with_guide_purpose – If True, the simulation mesh is assigned the guide purpose to hide it from rendering - but only if other GPrims are present under root_prim_path to provide visible geometry.

Returns:

True / False that indicates success of creation.

A PointBased visual prim without points at the default time returns False before the stage is modified.

ovphysx.utils.deformable.create_auto_volume_deformable_hierarchy(
stage: pxr.Usd.Stage,
root_prim_path: str | pxr.Sdf.Path,
simulation_tetmesh_path: str | pxr.Sdf.Path,
collision_tetmesh_path: str | pxr.Sdf.Path,
cooking_src_mesh_path: str | pxr.Sdf.Path,
simulation_hex_mesh_enabled: bool,
cooking_src_simplification_enabled: bool,
set_visibility_with_guide_purpose: bool = False,
) → bool#

Creates a volume deformable body from a stage hierachy and adds necessary prims and APIs. For single prim deformable bodies, use set_physics_volume_deformable_body on a UsdGeom.TetMesh.

Parameters:
  • stage – The stage

  • root_prim_path – Path to valid a UsdGeom.Imageable which cannot be a UsdGeom.Gprim. The UsdPhysics.DeformableBodyAPI is applied to this prim.

  • simulation_tetmesh_path – Path to where simulation mesh should be created or a valid UsdGeom.TetMesh.

  • collision_tetmesh_path – Path to where collision mesh should be created or a valid UsdGeom.TetMesh. CollisionAPI is applied to the collision mesh. May be identical to simulation_tetmesh_path.

  • cooking_src_mesh_path – Path to valid UsdGeom.Mesh that is used in cooking to generate the simulation and collision mesh. May be outside of root_prim_path sub-hierarchy.

  • simulation_hex_mesh_enabled – If True, simulation mesh is generated as a hexahedral mesh.

  • cooking_src_simplification_enabled – If True, PhysxAutoDeformableMeshSimplificationAPI is applied.

  • set_visibility_with_guide_purpose – If True, the simulation and collision meshes are assigned the guide purpose to hide them from rendering - but only if other GPrims are present under root_prim_path to provide visible geometry. If the simulation and collision meshes are the only geometry present and are distinct, then only the simulation mesh is assigned the guide purpose, leaving the collision mesh for visual representation.

Returns:

True / False that indicates success of creation.

A hexahedral mesh API that fails to apply returns False, on the same terms as a failed mesh simplification request. A caller that asked for a hexahedral simulation mesh is never told it succeeded with a tetrahedral one.

A PointBased visual prim without points at the default time returns False before the stage is modified.

ovphysx.utils.deformable.remove_auto_deformable_body(stage, prim_path: pxr.Sdf.Path)#

Removes the auto deformable body API set and its generated sub-component APIs.

Parameters:
  • stage – The stage.

  • prim_path – Path to the prim carrying PhysxAutoDeformableBodyAPI.

ovphysx.utils.deformable.remove_auto_deformable_hexahedral_mesh(stage, prim_path: pxr.Sdf.Path)#

Removes the hexahedral simulation mesh request from an auto deformable body.

Parameters:
  • stage – The stage.

  • prim_path – Path to the prim carrying PhysxAutoDeformableHexahedralMeshAPI.

ovphysx.utils.deformable.remove_auto_deformable_mesh_simplification(
stage,
prim_path: pxr.Sdf.Path,
)#

Removes the cooking-source simplification request from an auto deformable body.

Parameters:
  • stage – The stage.

  • prim_path – Path to the prim carrying PhysxAutoDeformableMeshSimplificationAPI.

ovphysx.utils.deformable.remove_deformable_body(stage, prim_path: pxr.Sdf.Path)#

Removes every deformable body API, and its local properties, from a prim and its subtree.

Both the single-prim and the hierarchical layouts are handled, and the per-instance deformable pose APIs are removed too. A simulation mesh prim that was generated automatically is left in place, since a caller may have taken ownership of it.

The sweep covers the supplied prim and every descendant, at any depth. It does not stop at a prim that resets its xform stack, so it also reaches pose APIs a caller applied outside the range the create_auto_*_deformable_hierarchy helpers author over.

UsdPhysics.CollisionAPI is the exception, and is taken only from a prim carrying a deformable simulation API, at any depth of that same sweep. Every other prim keeps it, a volume hierarchy’s separate collision mesh included. A collision API the caller applied to the simulation geometry goes with the body.

A property is removed from the current edit target, so one whose opinion arrives over a reference or an inherit arc, or from a stronger layer, keeps its resolved value after its API is gone. The API itself does go: the removal composes over such an arc.

Parameters:
  • stage – The stage.

  • prim_path – Path to the deformable body root prim.

ovphysx.utils.deformable.set_physics_surface_deformable_body(
stage,
prim_path: pxr.Sdf.Path,
) → bool#

Setup a surface deformable body based on a UsdGeom.Mesh at prim_path on stage and add necessary prims and APIs. For hierarchical setups use create_auto_surface_deformable_hierarchy.

Parameters:
  • stage – The stage

  • prim_path – Path to UsdGeom.Mesh ‘sim mesh’ to which the UsdPhysics.DeformableBodyAPI is applied to.

Returns:

True / False that indicates success of schema application

Missing default-time points or face topology return False before the stage is modified.

ovphysx.utils.deformable.set_physics_volume_deformable_body(
stage,
prim_path: pxr.Sdf.Path,
) → bool#

Setup a volume deformable body based on a UsdGeom.TetMesh at prim_path on stage and add necessary prims and APIs. For hierarchical setups use create_auto_volume_deformable_hierarchy.

Parameters:
  • stage – The stage

  • prim_path – Path to UsdGeom.TetMesh ‘sim mesh’ to which the UsdPhysics.DeformableBodyAPI is applied to.

Returns:

True / False that indicates success of schema application

Missing default-time points or tetrahedron indices return False before the stage is modified.

Schema introspection#

USD schema introspection and API-schema property manipulation.

These helpers work against the USD schema registry, so they cover schemas that were registered from a codeless plugin as well as compiled ones. That is what makes them useful outside Kit: a caller that only has pxr can still enumerate a PhysX API schema’s properties, snapshot them, and restore them.

How properties are reached#

PhysX schemas are codeless, so TfType.pythonClass is None for them and every property here is reached through the registry:

ovphysx.utils.schema.ancestor_has_api(name, prim)#

Check whether a prim or any ancestor has an API schema applied.

A prim that resets its xform stack terminates the ascent, because it no longer inherits its ancestors’ transform. The boundary is read with UsdGeom.Xformable.GetResetXformStack().

Parameters:
  • name – The API schema to look for, as a schema identifier string, a typed schema class, or a Tf.Type.

  • prim – The Usd.Prim to start from.

ovphysx.utils.schema.apply_api_schema_property_cache(cache, prim, multiple_api_token=None)#

Restore values captured by create_api_schema_property_cache().

Replays the cache through the generic Usd.Prim property API, so it works for codeless and compiled schemas alike. Apply the owning API schema to the prim first; this only authors properties.

Unset properties – a None attribute value, or None relationship targets – are skipped so that restoring does not author an opinion the snapshot did not have. The relationship test is targets is None and not not targets: an empty target list is how an authored-empty relationship is snapshotted. See create_api_schema_property_cache().

Parameters:
  • cache – The cache to replay.

  • prim – The Usd.Prim to author on.

  • multiple_api_token – The instance name, for a multiple-apply schema.

ovphysx.utils.schema.create_api_schema_property_cache(api, prim)#

Snapshot an API schema’s attribute and relationship values on a prim.

The result is consumed by apply_api_schema_property_cache(), which makes it possible to remove an API schema and restore its authored values later.

Only authored state is recorded. The snapshot holds one entry per property the API declares, and what that entry carries is the property’s authored value or targets, or nothing at all: an attribute that has only its schema fallback, and a relationship with no authored targets, are both snapshotted as unset.

“Authored” is USD’s own sense of the word throughout: an opinion exists somewhere in the prim’s composed property stack, as opposed to the value coming from a schema fallback. An opinion arriving over a reference, an inherit, a specialize, a variant or a weaker sublayer therefore counts as authored and is recorded. The snapshot does not tell a local opinion from a composed one; what it excludes is the fallback.

A relationship needs Usd.Relationship.HasAuthoredTargets for that distinction, because an unauthored relationship and one authored with an empty target list both compose to an empty list. An unauthored one is stored with None targets, as an unauthored attribute is stored with a None value; an authored one is stored with its target list whether or not that list is empty. apply_api_schema_property_cache() skips None targets and not the empty list, so a relationship authored with no targets is replayed and one carrying no opinion is left alone.

The cache exists for remove_api_schema_properties(), not for the removal of the API schema: Usd.Prim.RemoveAPI and ovphysx.utils.codeless.remove_api() drop the prim’s apiSchemas entry and leave every property authored under it in place.

remove_collider() strips the approximation and cooked-data APIs’ properties itself and leaves PhysxCollisionAPI’s, so removing those is the caller’s to ask for and snapshotting them first is how the caller gets them back.

Example:

from pxr import UsdPhysics

from ovphysx.utils import (
    apply_api_schema_property_cache,
    create_api_schema_property_cache,
    remove_api_schema_properties,
    remove_collider,
    set_collider,
)

# prim is a UsdGeom.Mesh set up as a convexHull collider, carrying
# authored physxCollision:contactOffset and physxCollision:restOffset
# and a physxConvexHullCollision:hullVertexLimit.
tuning = create_api_schema_property_cache("PhysxCollisionAPI", prim)

# Takes the hull API's own opinions with it; leaves the two offsets,
# which is why they have to be removed explicitly here.
remove_collider(prim)
remove_api_schema_properties("PhysxCollisionAPI", prim)

set_collider(prim, UsdPhysics.Tokens.convexDecomposition)
apply_api_schema_property_cache(tuning, prim)

The prim ends up approximated as a convex decomposition, carrying the two offsets it started with and no leftover physxConvexHullCollision opinion. The other attributes PhysxCollisionAPI declares stay unauthored, because the snapshot recorded no value for them.

Parameters:
  • api – The API schema type-name string or schema class.

  • prim – The Usd.Prim to read.

Returns:

[attributes, relationships], where each attribute entry is (name, value_type, value) and each relationship entry is (name, targets). The value type is the Sdf.ValueTypeName needed to recreate the property, a codeless schema having no class to name.

value and targets are both None for an unauthored property. targets is an empty list only for a relationship authored with no targets, which is what lets that opinion survive a restore.

ovphysx.utils.schema.create_multiple_api_schema_property_cache(
api,
prim,
api_prefix,
multiple_token,
)#

Snapshot one instance of a multiple-apply API schema’s properties.

Parameters:
  • api – The API schema type-name string or schema class.

  • prim – The Usd.Prim to read.

  • api_prefix – The property namespace prefix, e.g. “physxCookedData”.

  • multiple_token – The instance name.

Returns:

The same shape as create_api_schema_property_cache(), except that names are recorded as prefix:__INSTANCE_NAME__:name templates. apply_api_schema_property_cache() substitutes its multiple_api_token into them, so a snapshot can be replayed onto a different instance. It records authored state only, on the same terms – including None targets for a relationship instance with no authored ones, as against an empty list for one authored with none.

ovphysx.utils.schema.descendant_has_api(name, prim)#

Check whether a prim or any descendant has an API schema applied.

A prim that resets its xform stack terminates the descent, because its subtree no longer inherits the ancestor’s transform. The boundary is read with UsdGeom.Xformable.GetResetXformStack().

Parameters:
  • name – The API schema to look for, as a schema identifier string, a typed schema class, or a Tf.Type.

  • prim – The Usd.Prim to start from.

ovphysx.utils.schema.get_schema_attribute(
schema,
) → List[Tuple[str, pxr.Sdf.AttributeSpec]]#

List (name, spec) pairs for a schema’s attributes.

Parameters:

schema – A schema type-name string or schema class.

Returns:

(bare_property_name, Sdf.AttributeSpec) pairs. Read spec.typeName for the value type.

ovphysx.utils.schema.get_schema_instances(prim, schema_type_name)#

Get the instance names of a multiple-apply schema applied to a prim.

Parameters:
  • prim – The Usd.Prim to inspect.

  • schema_type_name – The multiple-apply schema type name.

ovphysx.utils.schema.get_schema_prim_def(schema)#

Get the registry prim definition for an applied API or concrete schema.

Parameters:

schema – A schema type-name string or schema class.

ovphysx.utils.schema.get_schema_property_names(schema)#

List the property names a schema registers.

Parameters:

schema – A schema type-name string or schema class.

ovphysx.utils.schema.get_schema_relationship(
schema,
) → List[Tuple[str, pxr.Sdf.RelationshipSpec]]#

List (name, spec) pairs for a schema’s relationships.

Parameters:

schema – A schema type-name string or schema class.

Returns:

(bare_property_name, Sdf.RelationshipSpec) pairs. See get_schema_attribute() for why this is a spec and not a class.

ovphysx.utils.schema.get_tf_type_compatible(schema_type_or_type_name)#

Resolve a schema identifier to a TfType, passing a TfType through.

Accepts a schema type-name string (the only form available for a codeless schema), a typed schema class, or an existing Tf.Type.

Parameters:

schema_type_or_type_name – A schema type-name string, schema class, or type.

ovphysx.utils.schema.has_schema(prim, schema_name)#

Check whether a prim has an applied schema, matching by name.

Parameters:
  • prim – The Usd.Prim to check.

  • schema_name – The applied schema name, e.g. “PhysicsRigidBodyAPI”.

ovphysx.utils.schema.remove_api_schema_properties(api, prim)#

Remove every property an API schema defines from a prim.

Parameters:
  • api – The API schema type-name string or schema class.

  • prim – The Usd.Prim to strip.

ovphysx.utils.schema.remove_multiple_api_schema_properties(
api,
prim,
api_prefix,
multiple_token,
)#

Remove one instance of a multiple-apply API schema’s properties.

Parameters:
  • api – The API schema type-name string or schema class.

  • prim – The Usd.Prim to strip.

  • api_prefix – The property namespace prefix, e.g. “physxCookedData”.

  • multiple_token – The instance name.

Simulation#

Stepping a running simulation and writing its output back to ovstage.

Every other submodule here authors a stage; this one drives a running simulation. step_and_write_to_ovstage() performs the whole step-read-write-back loop an application would otherwise spell out by hand, without that workflow becoming part of the core ovphysx.api.PhysX surface.

That makes this the one submodule whose helpers are not pure pxr: they need ovstage when called, and an attached PhysX instance to call them on. ovstage is therefore imported inside the function bodies, so import ovphysx.utils still needs nothing beyond pxr and the standard library and still loads no native library.

class ovphysx.utils.simulation.OvStageOutputCache(physx: PhysX)#

Reusable application-owned state for step_and_write_to_ovstage().

The cache binds to the exact OVStage attachment and lazily owns copies of scales derived from omni:fabric:worldMatrix and point-instancer pose arrays. It also reuses Warp buffers on each producing device. Call refresh() after authored transforms, point-instancer pose arrays, or topology change. Omit the cache from step_and_write_to_ovstage() to read current OVStage values on every call instead.

close() → None#

Release cache-owned wrappers and buffers. Safe to call repeatedly.

refresh() → None#

Discard owned snapshots and device-specific buffers.

ovphysx.utils.simulation.step_and_write_to_ovstage(
physx: PhysX,
*,
dt: float,
output_ordinal: int,
cache: OvStageOutputCache | None = None,
outputs: Mapping[SimObjectType, Sequence[str]] | None = None,
) → int#

Step once and write selected physics output to the attached OVStage.

Fixed rigid-body, articulation-link, and vehicle-wheel poses are combined with scale derived from the current omni:fabric:worldMatrix and written directly to that attribute. The helper never writes omni:xform or omni:resetXformStack. Point-instancer rigid-body poses are written to their native instancer-local positions and orientations arrays; unsimulated slots retain the current OVStage values.

By default the helper reads current OVStage values on every call and keeps no snapshots after returning. Passing an application-owned cache opts into retaining derived scale, point-instancer baselines, Warp buffers, and CUDA events across calls. Persistent borrowed OVStage views are never kept.

Other selected output is written to its shadow sim:<name> attribute. output_ordinal is caller-owned and must never be drained back into physics with ovphysx.api.PhysX.update_from_ovstage().

Parameters:
  • physx – Attached simulation instance to step and read.

  • dt – Simulation time step in seconds.

  • output_ordinal – OVStage ordinal used only for physics output.

  • cache – Optional application-owned snapshots and reusable buffers.

  • outputs – Optional object-type-to-attribute selection. None uses the documented default dynamic output set.

Returns:

Number of OVStage attributes written.

Raises:
  • RuntimeError – No OVStage is attached, or cache is bound to a different PhysX instance, a different attachment, or is closed.

  • TypeError – cache is neither None nor an OvStageOutputCache, or outputs is not a mapping of SimObjectType to a sequence of attribute-name strings.

  • ValueError – outputs selects only one of position / orientation for a rigid body, articulation link, or vehicle wheel. Fixed-pose types must select both together, since the helper composes a world matrix from the pair; select neither, or both, to avoid this.

Metadata keys and naming constants#

Constants shared by the authoring helpers.

Collected here rather than duplicated per module.

PhysX schemas are codeless, so PhysX schema tokens are spelled out here as string literals; refer to ovphysx.utils.codeless.

ovphysx.utils.constants.AXES_INDICES = {'X': 0, 'Y': 1, 'Z': 2}#

Maps an axis name to its index in a 3-vector.

ovphysx.utils.constants.COOKED_DATA_TOKENS = [pxr.UsdPhysics.Tokens.convexHull, pxr.UsdPhysics.Tokens.convexDecomposition, 'triangleMesh']#

The PhysxCookedDataAPI instance names, one per cooked representation. Each is the instance name of a multiple-apply API, so its buffer lives at physxCookedData:<token>:buffer.

The three values are "convexHull", "convexDecomposition" and "triangleMesh". They are spelled out here because the first two are read from UsdPhysics.Tokens, which the documentation build mocks along with the rest of pxr: the rendered value of this list therefore shows a mock placeholder in place of each of the two, beside triangleMesh as a real literal. Do not read the rendered list as the values.

ovphysx.utils.constants.MAX_FLOAT = 3.40282347e+38#

The largest finite value a USD float attribute can hold.

ovphysx.utils.constants.MESH_APPROXIMATIONS = {'sdf': 'PhysxSDFMeshCollisionAPI', 'sphereFill': 'PhysxSphereFillCollisionAPI', pxr.UsdPhysics.Tokens.boundingCube: None, pxr.UsdPhysics.Tokens.boundingSphere: None, pxr.UsdPhysics.Tokens.convexDecomposition: 'PhysxConvexDecompositionCollisionAPI', pxr.UsdPhysics.Tokens.convexHull: 'PhysxConvexHullCollisionAPI', pxr.UsdPhysics.Tokens.meshSimplification: 'PhysxTriangleMeshSimplificationCollisionAPI', pxr.UsdPhysics.Tokens.none: 'PhysxTriangleMeshCollisionAPI'}#

Maps a mesh approximation token to the identifier of the PhysX collision API schema carrying that approximation’s tuning parameters. A None value means the approximation is fully described by the token and needs no extra API. The values are schema identifier strings rather than typed classes because the PhysX schemas are codeless; apply them with ovphysx.utils.codeless.apply_api().

The eight entries are spelled out below, and the keys are the whole of what ovphysx.utils.set_collider() accepts as its approximation_shape:

  • "none" – "PhysxTriangleMeshCollisionAPI"

  • "convexHull" – "PhysxConvexHullCollisionAPI"

  • "convexDecomposition" – "PhysxConvexDecompositionCollisionAPI"

  • "meshSimplification" – "PhysxTriangleMeshSimplificationCollisionAPI"

  • "boundingCube" – None

  • "boundingSphere" – None

  • "sphereFill" – "PhysxSphereFillCollisionAPI"

  • "sdf" – "PhysxSDFMeshCollisionAPI"

Spelled out because six of the eight keys are read from UsdPhysics.Tokens, which the documentation build mocks along with the rest of pxr, so the rendered value of this dict shows a mock placeholder in place of each of those six keys. Do not read the rendered mapping as the mapping.

ovphysx.utils.constants.METADATA_ATTRIBUTE_NAME_LOCALSPACEVELOCITIES = 'physics:localSpaceVelocities'#

The customData dict key that makes the runtime read a rigid body’s authored velocities in the body frame instead of world space.

ovphysx.utils.constants.SCENE_UPDATE_TYPE_ASYNCHRONOUS = 'Asynchronous'#

the scene steps asynchronously.

Type:

physxScene:updateType value

ovphysx.utils.constants.SCENE_UPDATE_TYPE_DISABLED = 'Disabled'#

the scene does not step.

Type:

physxScene:updateType value

ovphysx.utils.constants.SCENE_UPDATE_TYPE_SYNCHRONOUS = 'Synchronous'#

the scene steps in the update thread.

Type:

physxScene:updateType value

ovphysx.utils.constants.TOKEN_SDF = 'sdf'#

Mesh approximation token for a signed-distance-field collider.

ovphysx.utils.constants.TOKEN_SPHERE_FILL = 'sphereFill'#

Mesh approximation token for a sphere-fill collider.

ovphysx.utils.constants.TOKEN_TRIANGLE_MESH = 'triangleMesh'#

Mesh approximation token for an exact triangle mesh collider.