Physics Schemas#

Physics behavior in a USD scene is described by schemas: typed sets of attributes and relationships applied to prims. ovphysx loads and simulates scenes authored with these schemas. This page explains the schema layers ovphysx understands and how to make the PhysX-specific ones available when you author with a stock usd-core.

Schema Layers#

  • USD Physics Schema (UsdPhysics) — the standard OpenUSD schema for annotating assets with physics: PhysicsScene, PhysicsRigidBodyAPI, PhysicsCollisionAPI, PhysicsMassAPI, PhysicsMaterialAPI, the joint types, and articulation APIs. It ships with stock usd-core and has typed Python bindings, for example UsdPhysics.RigidBodyAPI.Apply(prim). Refer to the OpenUSD UsdPhysics reference.

  • PhysX Schema (Physx*, codeless) — extends UsdPhysics with PhysX-specific functionality and tuning: PhysxSceneAPI (solver, GPU settings), PhysxRigidBodyAPI (CCD, sleep, stabilization), PhysxCollisionAPI (contact and rest offsets), PhysxForceAPI, joint extensions such as PhysxJointAxisAPI (refer to Joints), deformable extensions (refer to Deformables), and more. ovphysx ships this schema as codeless artifacts (plugInfo.json plus generatedSchema.usda, no compiled library).

  • Omni Physics Deformable Schema (codeless) — extends UsdPhysics with deformable bodies (OmniPhysicsDeformableBodyAPI and friends). Refer to Deformables.

The complete attribute set for each schema — types, defaults, and allowed values — is authoritative in the schema definitions themselves and is rendered in the Omni Physics documentation and the OpenUSD UsdPhysics reference. This guide describes intent, not full attribute definitions, so the two do not drift.

How ovphysx Ships the PhysX Schemas#

ovphysx exposes the PhysX USD schemas as codeless artifacts: a plugInfo.json (Type: resource) plus a generatedSchema.usda per module, with no compiled library. Codeless schemas carry no typed helper class — there is no PhysxSchema.PhysxRigidBodyAPI binding. You apply them by identifier and author their attributes generically.

Because they are codeless, the core UsdPhysics typed APIs (rigid body, collider, mass, scene) work out of the box with stock usd-core, while Physx* attributes require registering the codeless schemas first.

Making Schemas Available#

There are two registration paths, depending on which USD runtime is in play.

ovphysx’s bundled USD runtime#

When you run the simulator, ovphysx uses its bundled OV namespaced USD runtime. Importing ovphysx automatically calls register_schema_paths(), which appends ovphysx’s schema plugin path to OV_PXR_PLUGINPATH_2511 before the first USD stage open. In a process that mixes ovphysx with another USD-aware subsystem (for example ovrtx), call register_schema_paths() (and the peer subsystem’s equivalent) explicitly before the first stage open so USD’s schema registry sees every plugin root. See the USD coexistence notes in the Overview.

Authoring with a stock usd-core#

The codeless PhysX USD schemas shipped in ovphysx can be registered with any USD runtime — including stock usd-core from PyPI — without starting the simulator. This is useful for offline authoring, validation, and non-interactive tooling:

import sys

import ovphysx

try:
    from pxr import Plug, Tf, Usd
except ImportError:
    # Stock usd-core has no wheel for some platforms (e.g. linux-aarch64). The
    # codeless schemas still ship in the wheel; there is simply no stock USD
    # runtime to register them into here, so skip rather than fail.
    print("usd-core is not available on this platform; skipping codeless schema demo.")
    sys.exit(0)


def main() -> int:
    print("ovphysx version:", ovphysx.__version__)

    # Discover the codeless PhysX USD schema packages bundled with ovphysx.
    # Each path is a resources/ directory holding a codeless plugInfo.json
    # (Type=resource) and generatedSchema.usda -- no compiled library.
    schema_paths = ovphysx.codeless_schema_paths()
    print("Codeless schema packages:")
    for path in schema_paths:
        print("  ", path)

    # Register them with the stock usd-core runtime.
    registry = Plug.Registry()
    registered = []
    for path in schema_paths:
        registered.extend(registry.RegisterPlugins(str(path)))
    registered_names = sorted(plugin.name for plugin in registered)
    print("Registered USD plugins:", registered_names)
    assert "physxSchema" in registered_names, registered_names
    assert "omniUsdPhysicsDeformableSchema" in registered_names, registered_names

    # Codeless schemas carry no compiled C++/Python bindings, so apply API
    # schemas by their schema identifier and query with the generic USD API.
    stage = Usd.Stage.CreateInMemory()
    prim = stage.DefinePrim("/World/Box", "Cube")
    assert prim.ApplyAPI("PhysxRigidBodyAPI"), "failed to apply PhysxRigidBodyAPI"
    assert prim.ApplyAPI("PhysxCollisionAPI"), "failed to apply PhysxCollisionAPI"

    rigid_body_type = Tf.Type.FindByName("PhysxSchemaPhysxRigidBodyAPI")
    assert rigid_body_type != Tf.Type.Unknown, "PhysxRigidBodyAPI not in schema registry"
    assert prim.HasAPI(rigid_body_type), "prim is missing PhysxRigidBodyAPI after apply"

    print("Applied API schemas:", list(prim.GetAppliedSchemas()))
    print("Codeless PhysX schema registration succeeded.")
    return 0


if __name__ == "__main__":
    sys.exit(main())

After registration, apply the PhysX APIs by identifier and set attributes with USD’s generic attribute API:

from pxr import Sdf

prim.ApplyAPI("PhysxRigidBodyAPI")
prim.CreateAttribute("physxRigidBody:disableGravity", Sdf.ValueTypeNames.Bool).Set(True)

codeless_schema_paths() returns the per-module resources directories, and codeless_schema_root() returns the directory that holds them. Both are pure-Python and never trigger native loading, so they are safe to use in an authoring-only process.

Authoring Routes#

The same physics content can be authored two ways; both produce a .usda/.usd file that ovphysx loads identically.

  • Hand-authored .usda text. Apply schemas through the apiSchemas metadata list and set attributes directly. No Python or schema registration needed to write the file:

    def Cube "box" (
        prepend apiSchemas = ["PhysicsRigidBodyAPI", "PhysxRigidBodyAPI", "PhysicsCollisionAPI"]
    )
    {
        bool physxRigidBody:disableGravity = 0
    }
    
  • Python with a USD runtime. Use typed UsdPhysics bindings for core schemas and the codeless ApplyAPI pattern above for Physx* schemas.

Common pitfall. Using a typed PhysxSchema.* class instead of the codeless prim.ApplyAPI("Physx...") pattern silently no-ops with stock usd-core — there is no compiled PhysxSchema module. Register the codeless schemas and apply by identifier.

For a hands-on authoring walkthrough (scene, ground, rigid body, colliders), see the bundled ovphysx-usd-authoring skill and the per-topic pages under Simulation Setup.