Quickstart#
ovphysx is an SDK for ovstage/USD-based physics simulation, available as a Python wheel and a C/C++ package. This guide shows how to get started with both. You learn the required SDK layout, CMake configuration, runtime setup, and where to go next.
Prerequisites#
For both Python and C:
Prepare a simple USD file such as
scene.usdafor ovstage population.x86_64 only: a CPU with AVX (Advanced Vector Extensions). Pre-built ovphysx x86_64 binaries require AVX;
ovphysx_initialize()fails fast when AVX is unavailable. On Linux x86_64, check withgrep -qw avx /proc/cpuinfo. Linux aarch64 wheels are unaffected.Install CUDA Toolkit and a compatible NVIDIA driver (recommended, but can be skipped if only CPU simulation is used).
Quick Start by Language#
Python#
Install the wheel:
pip install ovphysx
import ovstage
import ovphysx
from ovphysx import PhysX
stage = ovstage.Stage("scene")
ovstage.population.open_usd(
stage, "scene.usda", ordinal=1, domains=ovstage.PopulationDomain.PHYSICS
)
physx = PhysX()
physx.attach_ovstage(stage, read_ordinal=1)
physx.step(1.0 / 60.0)
physx.detach_ovstage()
physx.release()
stage.destroy()
domains is an OR-combinable bitmask whose ovstage default (RENDERING) omits
physics. For arbitrary USD prefer ALL (equivalently PHYSICS | RENDERING);
PHYSICS alone is only safe when the content is known not to put physics under
native scene-graph instances — refer to
Population domains.
C/C++#
Download the ovphysx SDK package from the GitHub Releases page and extract it to a local path. You also need a C or C++ compiler and CMake — 3.16 or newer on Linux, 4.1 or newer on Windows.
Repository source builds fetch OVStage automatically from public PyPI. The manual download below is only for users of the prebuilt OVPhysX SDK.
ovstage is not part of the SDK. ovphysx binds to the application-supplied
ovstage, so the package ships no ovstage headers, library, or runtime. Download
the matching native archive for your platform from the
OVStage GitHub Releases
page and extract it to a separate directory beside ovphysx. This release uses
OVStage 0.1.0.346039, published under the v0.1.0 release. Do not overlay the
two package trees.
find_package(ovphysx) pulls it in via find_dependency(ovstage), so just add
both roots to CMAKE_PREFIX_PATH. This is required even if you never call ovstage because the
public ovphysx headers #include <ovstage/...>.
SDK Directory Layout
ovphysx/
├── SKILLS.md # Skills index
├── skills/ # Agent skills runbooks
├── include/ovphysx/ # Public headers (ovphysx.h, ovphysx_types.h, and related headers)
├── lib/ # Shared libraries and CMake package config
│ └── cmake/ovphysx/ # find_package(ovphysx) support
├── plugins/ # Carbonite, PhysX, and USD runtime plugins
│ └── gpu/ # GPU-only plugins (loaded only when GPU is enabled)
├── samples/ # CI-tested C sample source + USD data
├── docs/ # Documentation (HTML + Markdown)
├── LICENSE.txt
└── ovstage-THIRD-PARTY-NOTICES.txt
Build Your First App
CMakeLists.txt
The SDK ships a complete, CI-tested sample. Its CMake project links both the ovphysx and ovstage companion targets:
cmake_minimum_required(VERSION 3.16)
project(HelloWorldC C)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
find_package(ovphysx REQUIRED)
add_executable(hello_world_c main.c)
# Explicitly set the language to C (not C++)
set_source_files_properties(main.c PROPERTIES LANGUAGE C)
set_target_properties(hello_world_c PROPERTIES
C_STANDARD 11
C_STANDARD_REQUIRED ON
)
# Add compiler-specific flags to enforce strict C compilation
if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang")
# GCC/Clang: Add -Werror=implicit-function-declaration to catch C++ leakage
target_compile_options(hello_world_c PRIVATE
-Werror=implicit-function-declaration
-pedantic
)
endif()
if(MSVC)
# MSVC: Compile as C code explicitly
target_compile_options(hello_world_c PRIVATE /TC)
endif()
target_link_libraries(hello_world_c PRIVATE ovphysx::ovphysx ovphysx::ovstage)
target_include_directories(hello_world_c PRIVATE "${CMAKE_CURRENT_LIST_DIR}/../common")
get_filename_component(OVPHYSX_TEST_DATA_DIR "${CMAKE_CURRENT_LIST_DIR}/../../data" ABSOLUTE)
target_compile_definitions(hello_world_c PRIVATE
OVPHYSX_TEST_DATA="${OVPHYSX_TEST_DATA_DIR}"
)
if(WIN32)
ovphysx_copy_runtime_dlls(hello_world_c)
endif()
Source#
The sample creates and populates an ovstage instance, attaches it with the sealed read ordinal, waits for the physics step, and cleans up in lifetime-safe order:
#include "ovphysx/ovphysx.h"
#include "ovstage_sample.h"
#include <stdio.h>
static int run(void)
{
// Create PhysX instance with default args
ovphysx_create_args create_args = OVPHYSX_CREATE_ARGS_DEFAULT;
ovphysx_handle_t handle = 0;
ovphysx_result_t result = ovphysx_create_instance(&create_args, &handle);
if (result.status != OVPHYSX_API_SUCCESS) {
fprintf(stderr, "Failed to create PhysX instance\n");
ovphysx_shutdown();
return 1;
}
// Populate ovstage from USD and attach it to ovphysx
ovphysx_sample_stage_attachment_t stage_attachment = {0};
if (!ovphysx_sample_attach_usd_with_ovstage(
handle, OVPHYSX_TEST_DATA "/simple_physics_scene.usda", &stage_attachment)) {
fprintf(stderr, "Failed to attach ovstage scene\n");
ovphysx_destroy_instance(handle);
ovphysx_shutdown();
return 1;
}
// Step the simulation
ovphysx_enqueue_result_t step_result = ovphysx_step(handle, 0.016f);
if (step_result.status != OVPHYSX_API_SUCCESS) {
fprintf(stderr, "Failed to step simulation\n");
ovphysx_sample_destroy_stage(handle, &stage_attachment);
ovphysx_destroy_instance(handle);
ovphysx_shutdown();
return 1;
}
// Wait for step to complete
ovphysx_op_wait_result_t step_wait_result = {0};
ovphysx_result_t step_wait_status = ovphysx_wait_op(handle, step_result.op_index, UINT64_MAX, &step_wait_result);
int step_ok = (step_wait_status.status == OVPHYSX_API_SUCCESS && step_wait_result.num_errors == 0);
ovphysx_destroy_wait_result(&step_wait_result);
if (!step_ok) {
fprintf(stderr, "Simulation step failed\n");
ovphysx_sample_destroy_stage(handle, &stage_attachment);
ovphysx_destroy_instance(handle);
ovphysx_shutdown();
return 1;
}
printf("Simulation step completed successfully\n");
ovphysx_sample_destroy_stage(handle, &stage_attachment);
ovphysx_destroy_instance(handle);
ovphysx_shutdown();
printf("Cleanup complete\n");
return 0;
}
int main(void) {
ovphysx_result_t init_r = ovphysx_initialize();
if (init_r.status != OVPHYSX_API_SUCCESS) {
fprintf(stderr, "ovphysx_initialize() failed\n");
return 1;
}
int rc = run();
return rc;
}
Configure and Build
Point CMAKE_PREFIX_PATH at the SDK root (the directory containing include/,
lib/, and plugins/) and build the bundled sample:
cmake -B build -S /path/to/ovphysx/samples/c_samples/hello_world_c \
-DCMAKE_PREFIX_PATH="/path/to/ovphysx;/path/to/ovstage"
cmake --build build
Runtime Libraries (C/C++)#
Linux#
The CMake config bakes RPATH into your executable automatically.
No LD_LIBRARY_PATH manipulation is needed. Run the binary directly.
Windows#
Use the ovphysx_copy_runtime_dlls(<target>) helper provided by the CMake package
(already shown in the CMakeLists.txt example).
This copies the OVPhysX DLLs and plugins next to your executable. Keep the
separate OVStage package intact and add its bin, bin/plugins,
bin/plugins/omni.client.lib, and bin/plugins/omni.usd_resolver directories
to the process PATH before launch.
$env:OVSTAGE_ROOT = "C:\path\to\extracted\ovstage"
$env:PATH = "$env:OVSTAGE_ROOT\bin;$env:OVSTAGE_ROOT\bin\plugins;$env:OVSTAGE_ROOT\bin\plugins\omni.client.lib;$env:OVSTAGE_ROOT\bin\plugins\omni.usd_resolver;$env:PATH"
Result#
You now have a minimal C or C++ application that links against ovphysx::ovphysx, consumes an application-owned ovstage, and runs a simulation step.
Next Steps#
Full C API reference: refer to the C API Reference
More tutorials: Hello World, Tensor Bindings, Contact Binding