Tensor Bindings: Read and Write Simulation Data#

This tutorial shows how to read and write simulation data through tensor bindings after you attach an ovstage-populated scene. You learn how to use path patterns to bind multiple prims in one call.

Prerequisites#

  • Complete the Hello World tutorial.

  • Use a USD scene that contains physics-enabled prims matching your binding pattern.

For the physics concepts behind the quantities these tensors expose — rigid bodies, articulations, joints and drives, deformables — and how to author them in USD, refer to the Simulation Setup pages, starting with Rigid Bodies and Articulations.

Code Language#

Python#

        print("Creating tensor binding for DOF velocity targets...")
        velocity_target_binding = physx.create_tensor_binding(
            pattern="/World/articulation/articulationLink*",
            tensor_type=TensorType.ARTICULATION_DOF_VELOCITY_TARGET,
        )
        print(f"  DOF count: {velocity_target_binding.shape[1]}")

        print("Creating tensor binding for link poses...")
        link_pose_binding = physx.create_tensor_binding(
            pattern="/World/articulation/articulationLink*",
            tensor_type=TensorType.ARTICULATION_LINK_POSE,
        )
        print(f"  Link count: {link_pose_binding.shape[1]}, Pose dims: {link_pose_binding.shape[2]}")

        optional_pose_binding = physx.create_tensor_binding(
            pattern="/World/optionalRigidBodies/*",
            tensor_type=TensorType.RIGID_BODY_POSE,
        )
        if optional_pose_binding.count == 0:
            print("  Optional rigid body pose binding is empty")
        optional_pose_binding.destroy()
        optional_pose_binding = None

        num_dofs = velocity_target_binding.shape[1]
        velocity_targets = np.zeros(velocity_target_binding.shape, dtype=np.float32)
        for i in range(num_dofs):
            velocity_targets[0, i] = 25.0 if i % 2 == 0 else -25.0

        print("Setting DOF velocity targets (alternating +/-25 rad/s)...")
        velocity_target_binding.write(velocity_targets)
        print(f"  Velocity targets: {velocity_targets[0, :5]}... (first 5 DOFs)")

        print("\nRunning 1000 simulation steps...")
        link_poses = np.zeros(link_pose_binding.shape, dtype=np.float32)

        dt = 0.01
        for i in range(1000):
            physx.step(dt)
            physx.wait_all()

            if i % 100 == 0 or i == 999:
                link_pose_binding.read(link_poses)
                px, py, pz = link_poses[0, 0, 0:3]
                qx, qy, qz, qw = link_poses[0, 0, 3:7]
                roll_x_rad = math.atan2(2.0 * (qw * qx + qy * qz), 1.0 - 2.0 * (qx * qx + qy * qy))
                deg_x = roll_x_rad * 180.0 / math.pi
                print(
                    f"  Step {i:4d}: pos=({px:.6f}, {py:.6f}, {pz:.6f}), "
                    f"quat(xyzw)=({qx:.6f}, {qy:.6f}, {qz:.6f}, {qw:.6f}), "
                    f"rotation_x={deg_x:.2f} deg"
                )

        print("\nCompleted 1000 simulation steps successfully!")

C#

Create tensor bindings, write control targets, step, and read back state:

    // 3. Create tensor bindings
    // 3a. DOF velocity target binding (write control targets)
    ovphysx_tensor_binding_handle_t dof_target_binding = 0;
    ovphysx_tensor_binding_desc_t dof_target_desc = {
        .pattern = OVPHYSX_LITERAL("/World/articulation"),
        .tensor_type = OVPHYSX_TENSOR_ARTICULATION_DOF_VELOCITY_TARGET_F32
    };

    result = ovphysx_create_tensor_binding(handle, &dof_target_desc, &dof_target_binding);
    if (!check_result(result, "create DOF target binding")) {
        return destroy_instance_and_shutdown(handle);
    }

    // 3b. Articulation link pose binding
    ovphysx_tensor_binding_handle_t link_pose_binding = 0;
    ovphysx_tensor_binding_desc_t link_pose_desc = {
        .pattern = OVPHYSX_LITERAL("/World/articulation"),
        .tensor_type = OVPHYSX_TENSOR_ARTICULATION_LINK_POSE_F32
    };

    result = ovphysx_create_tensor_binding(handle, &link_pose_desc, &link_pose_binding);
    if (!check_result(result, "create articulation link pose binding")) {
        return destroy_instance_and_shutdown(handle);
    }

    printf("Tensor bindings created.\n");

    // 4. Query binding specs and allocate tensors
    ovphysx_tensor_spec_t dof_spec, link_pose_spec;

    result = ovphysx_get_tensor_binding_spec(handle, dof_target_binding, &dof_spec);
    if (!check_result(result, "get_tensor_binding_spec (dof target)")) {
        return destroy_instance_and_shutdown(handle);
    }

    result = ovphysx_get_tensor_binding_spec(handle, link_pose_binding, &link_pose_spec);
    if (!check_result(result, "get_tensor_binding_spec (link pose)")) {
        return destroy_instance_and_shutdown(handle);
    }

    printf("\nBinding specs:\n");
    printf("  Articulation DOFs: shape=[%lld, %lld], ndim=%d\n",
           (long long)dof_spec.shape[0], (long long)dof_spec.shape[1], dof_spec.ndim);
    printf("  Articulation link poses: shape=[%lld, %lld, %lld], ndim=%d\n",
           (long long)link_pose_spec.shape[0],
           (long long)link_pose_spec.shape[1],
           (long long)link_pose_spec.shape[2],
           link_pose_spec.ndim);

    // Allocate CPU tensors
    const size_t dof_count = (size_t)dof_spec.shape[0];
    const size_t dof_components = (size_t)dof_spec.shape[1];
    const size_t link_pose_batch = (size_t)link_pose_spec.shape[0];
    const size_t link_count = (size_t)link_pose_spec.shape[1];
    const size_t link_pose_components = (size_t)link_pose_spec.shape[2];

    TensorBuffer dof_target_tensor = make_tensor_f32_2d(dof_count, dof_components);
    TensorBuffer link_pose_tensor = make_tensor_f32_3d(link_pose_batch, link_count, link_pose_components);

    // 5. Set initial DOF velocity targets and simulate
    printf("\n=== Setting initial DOF velocity targets ===\n");

    // Initialize all targets to 0.0
    float* dof_target_data = (float*)dof_target_tensor.data;
    for (size_t i = 0; i < dof_count * dof_components; i++) {
        dof_target_data[i] = 0.0f;
    }
    printf("\n=== Writing initial DOF velocity targets ===\n");

    result = ovphysx_write_tensor_binding(handle, dof_target_binding, &dof_target_tensor.tensor, NULL);
    if (!check_result(result, "write initial DOF targets")) {
        destroy_tensor(&dof_target_tensor);
        destroy_tensor(&link_pose_tensor);
        return destroy_instance_and_shutdown(handle);
    }

    // 6. Simulation loop
    const float dt = 1.0f / 60.0f;
    const size_t link_index_to_print = (link_count > 0) ? (link_count - 1) : 0;

    printf("Running 120 simulation steps...\n");
    for (int step = 0; step < 120; ++step) {
        // Update DOF targets every 50 steps
        if (step % 50 == 0) {
            // Alternate between positive and negative target velocities
            float target_vel = ((step / 50) % 2 == 0) ? 50.0f : -50.0f;
            for (size_t i = 0; i < dof_count * dof_components; ++i) {
                // Alternate direction for each DOF
                dof_target_data[i] = (i % 2 == 0) ? target_vel : -target_vel;
            }

            result = ovphysx_write_tensor_binding(handle, dof_target_binding, &dof_target_tensor.tensor, NULL);
            if (!check_result(result, "write DOF targets")) {
                destroy_tensor(&dof_target_tensor);
                destroy_tensor(&link_pose_tensor);
                return destroy_instance_and_shutdown(handle);
            }
        }

        // Step simulation
        ovphysx_enqueue_result_t step_result = ovphysx_step(handle, dt);
        if (step_result.status != OVPHYSX_API_SUCCESS) {
            fprintf(stderr, "ERROR in step enqueue (status=%d)\n", (int)step_result.status);
            {
                ovphysx_string_t err = ovphysx_get_last_error();
                if (err.ptr && err.length > 0)
                    fprintf(stderr, "  %.*s\n", (int)err.length, err.ptr);
            }
            destroy_tensor(&dof_target_tensor);
            destroy_tensor(&link_pose_tensor);
            return destroy_instance_and_shutdown(handle);
        }
        if (!wait_op(handle, step_result.op_index, "step")) {
            destroy_tensor(&dof_target_tensor);
            destroy_tensor(&link_pose_tensor);
            return destroy_instance_and_shutdown(handle);
        }

        // Read and print state every 30 steps
        if (step % 30 == 0) {
            // Read articulation link poses
            result = ovphysx_read_tensor_binding(handle, link_pose_binding, &link_pose_tensor.tensor);
            if (!check_result(result, "read articulation link poses")) {
                destroy_tensor(&dof_target_tensor);
                destroy_tensor(&link_pose_tensor);
                return destroy_instance_and_shutdown(handle);
            }

            const float* link_pose_data = (const float*)link_pose_tensor.data;

            size_t articulation_index = 0;
            size_t link_pose_offset = (articulation_index * link_count + link_index_to_print) * link_pose_components;
            printf("Step %3d | Link %zu pos=(%.3f, %.3f, %.3f) quat=(%.3f, %.3f, %.3f, %.3f)\n",
                   step,
                   link_index_to_print,
                   link_pose_data[link_pose_offset + 0],
                   link_pose_data[link_pose_offset + 1],
                   link_pose_data[link_pose_offset + 2],
                   link_pose_data[link_pose_offset + 3],
                   link_pose_data[link_pose_offset + 4],
                   link_pose_data[link_pose_offset + 5],
                   link_pose_data[link_pose_offset + 6]);

        }
    }

    // Cleanup
    printf("\n=== Cleanup ===\n");

    destroy_tensor(&dof_target_tensor);
    destroy_tensor(&link_pose_tensor);

    ovphysx_destroy_tensor_binding(handle, dof_target_binding);
    ovphysx_destroy_tensor_binding(handle, link_pose_binding);

    printf("=== Articulation control sample completed successfully ===\n");

For GPU tensor bindings with CUDA, see tensor_bindings_gpu_c/ in the samples directory. GPU dynamics are enabled by default (physxScene:enableGPUDynamics defaults to true); set it to false to opt into CPU dynamics. For maximum performance in tensor-heavy loops, GPU dynamics alone is not enough: enable DirectGPU TensorAPI before creating the PhysX instance with /physics/suppressReadback=true. See GPU Warmup and Determinism.

Empty Optional Bindings#

A tensor binding that matches zero prims is valid. This is useful when absence is a legitimate result for the current scene, such as optional assets or broad inspection queries. Empty bindings remain zero-count views; if topology changes and matching prims are added or recreated, destroy the old binding and create a new one. For optional queries, keep the default raise_if_empty=False and check binding.count before allocating or reading tensors. Use raise_if_empty=True only when zero matches are a configuration error for your application.

Point-instancer limitation. TensorBindingsAPI does not expose per-instance rows for rigid bodies created by UsdGeom.PointInstancer. With the default raise_if_empty=False, a rigid-body binding that targets only the point instancer has count zero; the opt-in raise_if_empty=True mode raises as described above. Use the ovstage output read API for simulated instance readback. For control, author the point instancer’s positions, orientations, velocities, and angularVelocities arrays through ovstage and pass those control ordinals to update_from_ovstage(). Use standalone rigid-body prims when per-body tensor bindings are required.

Binding Lifetime#

Tensor bindings are views of the physics objects realized for the current stage. Create them after loading USD and reuse them across simulation steps. A normal step() or step_sync() does not invalidate a binding.

Do not keep cached bindings across application-owned topology changes. Before reset(), before removing USD data that contains bound objects, or before loading or reparsing a stage so bound objects are destroyed and recreated, destroy cached bindings when practical. If a stale binding survives one of those lifecycle operations, only destroy it; do not read or write through it. Create a replacement binding after the operation completes. In reset-heavy episode code, the reset path should clear cached bindings because that path is where the application changes the stage.

Tensor Type Reference#

Use this table to pre-allocate tensors without probing binding.shape at runtime. Python callers can also inspect binding.spec for the native DLPack metadata returned by ovphysx_get_tensor_binding_spec(). Allocate buffers from binding.shape and binding.dtype; most tensor types are float32, but types such as TensorType.RIGID_BODY_DISABLE_SIMULATION report uint8.

Symbols:

  • N: rigid body count in the binding

  • A: articulation count in the binding

  • L: max link count across matched articulations

  • D: max DOF count across matched articulations

  • T: max tendon count across matched articulations (fixed or spatial, depending on type)

  • M: generalized coordinate count — numDofs for fixed-base, numDofs + 6 for floating-base articulations

  • S: max collision shape count per body/link in the binding

  • R, C: Jacobian shape from getJacobianShape() — fixed-base: R=L*6, C=D; floating-base: R=(L-1)*6+6, C=D+6

  • B: volume deformable body count in the binding

  • V: max simulation node count across matched volume deformables

  • Vr: max rest node count across matched volume deformables

  • E: max simulation element count across matched volume deformables (tetrahedra, K=4)

  • F: max collision element count across matched volume deformables; K = getNumNodesPerElement() (4 for tetmesh)

  • P: deformable material count in the binding

  • Bs: surface deformable body count in the binding

  • Vs: max simulation node count across matched surface deformables

  • Es: max simulation element count across matched surface deformables (triangles, K=3)

Rigid Body State

Constant

Shape

Dimensionality

Read

Write

Component layout

Behavioral note

OVPHYSX_TENSOR_RIGID_BODY_POSE_F32

(N, 7)

2D

yes

yes

pos.xyz + quat.xyzw

World-frame rigid body transforms

OVPHYSX_TENSOR_RIGID_BODY_VELOCITY_F32

(N, 6)

2D

yes

yes

lin.xyz + ang.xyz

World-frame linear and angular velocity

OVPHYSX_TENSOR_RIGID_BODY_ACCELERATION_F32

(N, 6)

2D

yes

no

lin_acc.xyz + ang_acc.xyz

World-frame linear and angular acceleration

OVPHYSX_TENSOR_RIGID_BODY_FORCE_F32

(N, 3)

2D

no

yes

force.xyz

Write-only force at center of mass (control input)

OVPHYSX_TENSOR_RIGID_BODY_WRENCH_F32

(N, 9)

2D

no

yes

force.xyz + torque.xyz + pos.xyz

Write-only wrench-at-position in world frame

Rigid Body Properties (standalone, non-articulated bodies)

Constant

Shape

Dimensionality

Read

Write

Component layout

Behavioral note

OVPHYSX_TENSOR_RIGID_BODY_MASS_F32

(N,)

1D

yes

yes

mass scalar

Scalar mass per rigid body

OVPHYSX_TENSOR_RIGID_BODY_INV_MASS_F32

(N,)

1D

yes

no

inverse mass scalar

Computed from mass; read-only

OVPHYSX_TENSOR_RIGID_BODY_INERTIA_F32

(N, 9)

2D

yes

yes

row-major 3x3

Inertia tensor in body frame

OVPHYSX_TENSOR_RIGID_BODY_INV_INERTIA_F32

(N, 9)

2D

yes

no

row-major 3x3

Computed from inertia; read-only

OVPHYSX_TENSOR_RIGID_BODY_COM_POSE_F32

(N, 7)

2D

yes

yes

pos.xyz + quat.xyzw

COM local pose in body frame

Rigid body property tensors in this table are CPU tensors even when the simulation is running on GPU. State tensors such as pose, velocity, acceleration, force, and wrench use the simulation device.

For Python bindings, binding.prim_paths returns row metadata only; tensor reads and writes keep using the shapes above. Rigid-body bindings return one rigid body prim path per row. Articulation bindings return one articulation root prim path per A row; link names remain available through binding.body_names.

Rigid Body Shape Properties

Constant

Shape

Dimensionality

Read

Write

Component layout

Behavioral note

OVPHYSX_TENSOR_RIGID_BODY_SHAPE_FRICTION_AND_RESTITUTION_F32

(N, S, 3)

3D

yes

yes

(static_friction, dynamic_friction, restitution)

Per-shape material properties

OVPHYSX_TENSOR_RIGID_BODY_CONTACT_OFFSET_F32

(N, S)

2D

yes

yes

offset scalar per shape

Distance at which contacts are generated

OVPHYSX_TENSOR_RIGID_BODY_REST_OFFSET_F32

(N, S)

2D

yes

yes

offset scalar per shape

Rest separation between shapes

Shape property tensors in this table are CPU tensors even when the simulation is running on GPU.

Volume Deformable Body State

Symbols: B = volume deformable body count, V = max simulation nodes, Vr = max rest nodes, E = max simulation elements (tetrahedra, K=4), F = max collision elements (triangles, K=3).

Constant

Shape

Dimensionality

Read

Write

Component layout

Behavioral note

OVPHYSX_TENSOR_DEFORMABLE_SIM_NODAL_POSITION_F32

(B, V, 3)

3D

yes

yes

pos.xyz

Simulation mesh node positions

OVPHYSX_TENSOR_DEFORMABLE_SIM_NODAL_VELOCITY_F32

(B, V, 3)

3D

yes

yes

vel.xyz

Simulation mesh node velocities

OVPHYSX_TENSOR_DEFORMABLE_SIM_KINEMATIC_TARGET_F32

(B, V, 4)

3D

yes

yes

pos.xyz + flag

Simulation mesh kinematic targets

OVPHYSX_TENSOR_DEFORMABLE_REST_NODAL_POSITION_F32

(B, Vr, 3)

3D

yes

no

pos.xyz

Rest mesh node positions

OVPHYSX_TENSOR_DEFORMABLE_SIM_ELEMENT_INDICES_S32

(B, E, 4)

3D

yes

no

int32 node indices

Tetrahedral simulation element connectivity

OVPHYSX_TENSOR_DEFORMABLE_COLLISION_ELEMENT_INDICES_S32

(B, F, K)

3D

yes

no

int32 node indices

Collision element connectivity; K=4 for volume tetmesh

Volume deformable body tensors require DirectGPU mode. Enable /physics/suppressReadback=true before constructing the PhysX instance.

Surface Deformable Body State

Symbols: Bs = surface deformable body count, Vs = max simulation nodes, Vr = max rest nodes, Es = max simulation elements (triangles, K=3).

Constant

Shape

Dimensionality

Read

Write

Component layout

Behavioral note

OVPHYSX_TENSOR_SURFACE_DEFORMABLE_SIM_POSITION_F32

(Bs, Vs, 3)

3D

yes

yes

pos.xyz

Simulation mesh node positions

OVPHYSX_TENSOR_SURFACE_DEFORMABLE_SIM_VELOCITY_F32

(Bs, Vs, 3)

3D

yes

yes

vel.xyz

Simulation mesh node velocities

OVPHYSX_TENSOR_SURFACE_DEFORMABLE_REST_POSITION_F32

(Bs, Vr, 3)

3D

yes

no

pos.xyz

Rest mesh node positions

OVPHYSX_TENSOR_SURFACE_DEFORMABLE_SIM_ELEMENT_INDICES_S32

(Bs, Es, 3)

3D

yes

no

int32 node indices

Triangular simulation element connectivity

Surface deformable body tensors require DirectGPU mode. Enable /physics/suppressReadback=true before constructing the PhysX instance.

Deformable Material Properties

Constant

Shape

Dimensionality

Read

Write

Component layout

Behavioral note

OVPHYSX_TENSOR_DEFORMABLE_MATERIAL_DYNAMIC_FRICTION_F32

(P,)

1D

yes

yes

scalar

Dynamic friction per deformable material

OVPHYSX_TENSOR_DEFORMABLE_MATERIAL_YOUNGS_MODULUS_F32

(P,)

1D

yes

yes

scalar

Young’s modulus per deformable material

OVPHYSX_TENSOR_DEFORMABLE_MATERIAL_POISSONS_RATIO_F32

(P,)

1D

yes

yes

scalar

Poisson’s ratio per deformable material

Deformable material property tensors in this table are CPU tensors even when the simulation is running on GPU.

Articulation Root State

Constant

Shape

Dimensionality

Read

Write

Component layout

Behavioral note

OVPHYSX_TENSOR_ARTICULATION_ROOT_POSE_F32

(A, 7)

2D

yes

yes

pos.xyz + quat.xyzw

Root body transform per articulation

OVPHYSX_TENSOR_ARTICULATION_ROOT_VELOCITY_F32

(A, 6)

2D

yes

yes

lin.xyz + ang.xyz

Root body velocity per articulation

Articulation Link State

Constant

Shape

Dimensionality

Read

Write

Component layout

Behavioral note

OVPHYSX_TENSOR_ARTICULATION_LINK_POSE_F32

(A, L, 7)

3D

yes

no

pos.xyz + quat.xyzw

Per-link pose; padded links are zero

OVPHYSX_TENSOR_ARTICULATION_LINK_VELOCITY_F32

(A, L, 6)

3D

yes

no

lin.xyz + ang.xyz

Per-link velocity; read-only

OVPHYSX_TENSOR_ARTICULATION_LINK_ACCELERATION_F32

(A, L, 6)

3D

yes

no

lin_acc.xyz + ang_acc.xyz

Per-link linear and angular acceleration; read-only

OVPHYSX_TENSOR_ARTICULATION_LINK_WRENCH_F32

(A, L, 9)

3D

no

yes

force.xyz + torque.xyz + pos.xyz

Write-only per-link external wrench

Articulation DOF State and Control

Constant

Shape

Dimensionality

Read

Write

Component layout

Behavioral note

OVPHYSX_TENSOR_ARTICULATION_DOF_POSITION_F32

(A, D)

2D

yes

yes

joint position scalar per DOF

Joint-space position in articulation DOF order

OVPHYSX_TENSOR_ARTICULATION_DOF_VELOCITY_F32

(A, D)

2D

yes

yes

joint velocity scalar per DOF

Joint-space velocity in articulation DOF order

OVPHYSX_TENSOR_ARTICULATION_DOF_POSITION_TARGET_F32

(A, D)

2D

yes

yes

target position scalar per DOF

Position-control targets

OVPHYSX_TENSOR_ARTICULATION_DOF_VELOCITY_TARGET_F32

(A, D)

2D

yes

yes

target velocity scalar per DOF

Velocity-control targets

OVPHYSX_TENSOR_ARTICULATION_DOF_ACTUATION_FORCE_F32

(A, D)

2D

yes

yes

actuation scalar per DOF

Readback is from staging buffer; may differ from solver-applied force

Articulation DOF Properties

Constant

Shape

Dimensionality

Read

Write

Component layout

Behavioral note

OVPHYSX_TENSOR_ARTICULATION_DOF_STIFFNESS_F32

(A, D)

2D

yes

yes

stiffness scalar per DOF

PD position-control stiffness

OVPHYSX_TENSOR_ARTICULATION_DOF_DAMPING_F32

(A, D)

2D

yes

yes

damping scalar per DOF

PD velocity-control damping

OVPHYSX_TENSOR_ARTICULATION_DOF_LIMIT_F32

(A, D, 2)

3D

yes

yes

(lower, upper) per DOF

Joint position limits

OVPHYSX_TENSOR_ARTICULATION_DOF_MAX_VELOCITY_F32

(A, D)

2D

yes

yes

max velocity scalar per DOF

Per-DOF velocity clamp

OVPHYSX_TENSOR_ARTICULATION_DOF_MAX_FORCE_F32

(A, D)

2D

yes

yes

max force scalar per DOF

Per-DOF force/torque clamp

OVPHYSX_TENSOR_ARTICULATION_DOF_ARMATURE_F32

(A, D)

2D

yes

yes

armature scalar per DOF

Added inertia at each DOF

OVPHYSX_TENSOR_ARTICULATION_DOF_FRICTION_PROPERTIES_F32

(A, D, 3)

3D

yes

yes

(static, dynamic, viscous) per DOF

Friction coefficients at each DOF

Articulation Body Properties

Constant

Shape

Dimensionality

Read

Write

Component layout

Behavioral note

OVPHYSX_TENSOR_ARTICULATION_BODY_MASS_F32

(A, L)

2D

yes

yes

mass scalar per link

Scalar mass per articulation link

OVPHYSX_TENSOR_ARTICULATION_BODY_COM_POSE_F32

(A, L, 7)

3D

yes

yes

pos.xyz + quat.xyzw

COM local pose in body frame per link

OVPHYSX_TENSOR_ARTICULATION_BODY_INERTIA_F32

(A, L, 9)

3D

yes

yes

row-major 3x3

Inertia tensor in COM frame per link

OVPHYSX_TENSOR_ARTICULATION_BODY_INV_MASS_F32

(A, L)

2D

yes

no

inverse mass scalar per link

Computed from mass; read-only

OVPHYSX_TENSOR_ARTICULATION_BODY_INV_INERTIA_F32

(A, L, 9)

3D

yes

no

row-major 3x3

Computed from inertia; read-only

Articulation Shape Properties

Constant

Shape

Dimensionality

Read

Write

Component layout

Behavioral note

OVPHYSX_TENSOR_ARTICULATION_SHAPE_FRICTION_AND_RESTITUTION_F32

(A, S, 3)

3D

yes

yes

(static_friction, dynamic_friction, restitution)

Per-shape material properties per link

OVPHYSX_TENSOR_ARTICULATION_CONTACT_OFFSET_F32

(A, S)

2D

yes

yes

offset scalar per shape

Distance at which contacts are generated

OVPHYSX_TENSOR_ARTICULATION_REST_OFFSET_F32

(A, S)

2D

yes

yes

offset scalar per shape

Rest separation between shapes

Shape property tensors in this table are CPU tensors even when the simulation is running on GPU.

Articulation Dynamics Queries (read-only)

Constant

Shape

Dimensionality

Read

Write

Component layout

Behavioral note

OVPHYSX_TENSOR_ARTICULATION_JACOBIAN_F32

(A, R, C)

3D

yes

no

row-major

Shape from getJacobianShape(); see R, C in symbol legend above

OVPHYSX_TENSOR_ARTICULATION_MASS_MATRIX_F32

(A, M, M)

3D

yes

no

row-major square

Generalized mass matrix; shape from getGeneralizedMassMatrixShape()

OVPHYSX_TENSOR_ARTICULATION_CORIOLIS_AND_CENTRIFUGAL_FORCE_F32

(A, M)

2D

yes

no

force scalar per generalized coordinate

Combined Coriolis and centrifugal forces

OVPHYSX_TENSOR_ARTICULATION_GRAVITY_FORCE_F32

(A, M)

2D

yes

no

force scalar per generalized coordinate

Gravity compensation forces

OVPHYSX_TENSOR_ARTICULATION_LINK_INCOMING_JOINT_FORCE_F32

(A, L, 6)

3D

yes

no

force.xyz + torque.xyz

Incoming joint force and torque per link

OVPHYSX_TENSOR_ARTICULATION_DOF_PROJECTED_JOINT_FORCE_F32

(A, D)

2D

yes

no

scalar per DOF

Projected joint forces

Fixed Tendon Properties

Constant

Shape

Dimensionality

Read

Write

Component layout

Behavioral note

OVPHYSX_TENSOR_ARTICULATION_FIXED_TENDON_STIFFNESS_F32

(A, T)

2D

yes

yes

stiffness scalar per tendon

Requires articulation with fixed tendons

OVPHYSX_TENSOR_ARTICULATION_FIXED_TENDON_DAMPING_F32

(A, T)

2D

yes

yes

damping scalar per tendon

Requires articulation with fixed tendons

OVPHYSX_TENSOR_ARTICULATION_FIXED_TENDON_LIMIT_STIFFNESS_F32

(A, T)

2D

yes

yes

limit stiffness scalar per tendon

Requires articulation with fixed tendons

OVPHYSX_TENSOR_ARTICULATION_FIXED_TENDON_LIMIT_F32

(A, T, 2)

3D

yes

yes

(lower, upper) per tendon

Fixed tendon position limits

OVPHYSX_TENSOR_ARTICULATION_FIXED_TENDON_REST_LENGTH_F32

(A, T)

2D

yes

yes

rest length scalar per tendon

Requires articulation with fixed tendons

OVPHYSX_TENSOR_ARTICULATION_FIXED_TENDON_OFFSET_F32

(A, T)

2D

yes

yes

offset scalar per tendon

Requires articulation with fixed tendons

Spatial Tendon Properties

Constant

Shape

Dimensionality

Read

Write

Component layout

Behavioral note

OVPHYSX_TENSOR_ARTICULATION_SPATIAL_TENDON_STIFFNESS_F32

(A, T)

2D

yes

yes

stiffness scalar per tendon

Requires articulation with spatial tendons

OVPHYSX_TENSOR_ARTICULATION_SPATIAL_TENDON_DAMPING_F32

(A, T)

2D

yes

yes

damping scalar per tendon

Requires articulation with spatial tendons

OVPHYSX_TENSOR_ARTICULATION_SPATIAL_TENDON_LIMIT_STIFFNESS_F32

(A, T)

2D

yes

yes

limit stiffness scalar per tendon

Requires articulation with spatial tendons

OVPHYSX_TENSOR_ARTICULATION_SPATIAL_TENDON_OFFSET_F32

(A, T)

2D

yes

yes

offset scalar per tendon

Requires articulation with spatial tendons

For canonical enum definitions and low-level semantics, see include/ovphysx/ovphysx_types.h.

Result#

After this tutorial, you can create tensor bindings, push batched simulation inputs, and read back batched results.