Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ Backend-neutral physics runtime components for OpenUSD-based applications.

> **Status: Phase 1 core extraction.** The repository builds and installs
> `physicsCore` and `physicsJolt`; neutral rigid-transform values, typed
> handles, and validated box/body/fixed-constraint descriptors are
> implemented, but rigid-body runtime behavior, an OpenUSD bridge, and a
> solver backend are not. The
> handles, validated box/body/fixed-constraint descriptors, and the
> single-owner world contract are implemented, but optional query contracts,
> an OpenUSD bridge, and a solver backend are not. The
> [capability matrix](docs/reference/CAPABILITY_MATRIX.md) is the only page
> that states what exists, and the [current roadmap](docs/roadmap/current.md)
> states what comes next.
Expand Down Expand Up @@ -56,7 +56,7 @@ their backend.

| Component | Kind | Role | State |
| --- | --- | --- | --- |
| `physicsCore` | plain C++ library | Handles, descriptors, world lifecycle, state, and optional query contracts; no OpenUSD and no backend SDK | neutral values, handles, and validated descriptors present; remaining runtime API planned |
| `physicsCore` | plain C++ library | Handles, descriptors, world lifecycle, state, and optional query contracts; no OpenUSD and no backend SDK | neutral values, handles, descriptors, and world contract present; optional queries planned |
| `physicsJolt` | plain C++ library | First rigid-body backend implementing `physicsCore` | package scaffold present; backend unavailable |
| `physicsUsd` | OpenUSD-facing C++ library | Translate standard `UsdPhysics` declarations to runtime descriptors and maintain transient prim/resource mappings | planned |
| `secondaryMotion` | plain C++ library | Solver-neutral spring-chain and collider contracts | deferred until the rigid-body boundary is extracted |
Expand Down
5 changes: 3 additions & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ reference reports what exists, and the roadmap contains incomplete work.

**Current tree (2026-09-22): Phase 1 core extraction.** The root build,
packages, boundary checks, and installed-consumer test exist. Neutral rigid
transform values and typed handles are implemented; descriptors, world
behavior, a solver backend, an OpenUSD bridge, and a release are not. The
transform values, typed handles, validated descriptors, and the single-owner
world contract are implemented; optional queries, a solver backend, an OpenUSD
bridge, and a release are not. The
[capability matrix](reference/CAPABILITY_MATRIX.md) is the only page that may
claim implementation status.

Expand Down
6 changes: 3 additions & 3 deletions docs/architecture/PACKAGE_CONTRACT.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

> **Status: accepted, revised 2026-09-22.** `physicsCore` and `physicsJolt`
> install and pass a clean-prefix consumer test. `physicsCore` now includes
> neutral values, typed handles, and validated descriptors; world behavior
> remains unimplemented.
> neutral values, typed handles, validated descriptors, typed errors, and the
> single-owner world interface and validation surface.

## 1. Purpose

Expand All @@ -15,7 +15,7 @@ not need this repository's source tree.

| Package | Imported target | Provides | Planned phase |
| --- | --- | --- | --- |
| `physicsCore` | `physicsCore::physicsCore` | Version surface plus neutral vector, quaternion, transform, typed handles, validated box/body/fixed-constraint descriptors, and semantic collision filters; world and query contracts follow in Phase 1 | values, handles, and descriptors present; runtime Phase 1 |
| `physicsCore` | `physicsCore::physicsCore` | Version surface plus neutral vector, quaternion, transform, typed handles, validated box/body/fixed-constraint descriptors, semantic collision filters, typed errors, and the world lifecycle/state interface; optional query contracts follow in Phase 1 | values, handles, descriptors, errors, and world contract present; queries remain Phase 1 |
| `physicsJolt` | `physicsJolt::physicsJolt` | Phase 0 explicit unavailable status; Jolt-backed world construction follows in Phase 2 | scaffold present; backend Phase 2 |
| `physicsUsd` | `physicsUsd::physicsUsd` | USD translation, mappings, and synchronization records | 4 |
| `secondaryMotion` | `secondaryMotion::secondaryMotion` | generic secondary-motion contracts | 6, if admitted |
Expand Down
8 changes: 4 additions & 4 deletions docs/architecture/WORKSPACE.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ that contradicts it updates this document first, in a focused change.

| Identity | Kind | Directory | Planned manifest | Role | Created in | Status |
| --- | --- | --- | --- | --- | --- | --- |
| `physicsCore` | plain static CMake library | `libs/physicsCore/` | `openstrata.library.yaml` | Solver-neutral value types, handles, descriptors, world lifecycle, state, validation, and optional query contracts. No OpenUSD or backend SDK. | Phase 0 scaffold; Phase 1 runtime | values, handles, and validated descriptors implemented; remaining runtime planned |
| `physicsCore` | plain static CMake library | `libs/physicsCore/` | `openstrata.library.yaml` | Solver-neutral value types, handles, descriptors, world lifecycle, state, validation, and optional query contracts. No OpenUSD or backend SDK. | Phase 0 scaffold; Phase 1 runtime | values, handles, validated descriptors, and world contract implemented; optional queries planned |
| `physicsJolt` | plain static CMake library | `backends/physicsJolt/` | `openstrata.library.yaml` | Jolt implementation of `physicsCore`; owns Jolt initialization, filters, jobs, resources, stepping, and queries. | Phase 0 scaffold; Phase 2 backend | scaffolded; backend unavailable |
| `physicsUsd` | plain static CMake library | `libs/physicsUsd/` | `openstrata.library.yaml` | Standard `UsdPhysics` to core descriptors, transform conversion, transient scene/resource mapping, and synchronization records. | Phase 4 | reserved |

The Phase 0 targets established package and dependency boundaries.
`physicsCore` now has supported value, handle, and descriptor slices, while
its package as a whole remains partial. `physicsJolt` remains a partial
unavailable scaffold.
`physicsCore` now has supported value, handle, descriptor, and world-contract
slices, while its package as a whole remains partial. `physicsJolt` remains a
partial unavailable scaffold.

### 1.2 Later, only when the responsibility is real

Expand Down
39 changes: 25 additions & 14 deletions docs/design/RIGID_BODY_CONTRACT.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# Rigid-body runtime contract

> **Status: proposed, revised 2026-09-22.** This document describes the
> intended extraction target. Neutral values, handles, and descriptors are
> implemented; see the [capability matrix](../reference/CAPABILITY_MATRIX.md)
> for the exact current boundary.
> intended extraction target. Neutral values, handles, descriptors, typed
> errors, and the single-owner world interface are implemented; see the
> [capability matrix](../reference/CAPABILITY_MATRIX.md) for the exact current
> boundary.

## 1. Purpose

Expand Down Expand Up @@ -101,11 +102,13 @@ destroy constraint -> destroy body -> destroy unused shape
```

Destroying an invalid or stale handle must not access freed backend memory.
The contract must define whether an operation reports failure or is idempotent
before Phase 1 freezes the API.
Destruction returns `false` for an unknown, stale, cross-world, or already
destroyed handle. Destroying a body also destroys its dependent constraints;
destroying an in-use shape fails.

A world reset destroys every transient resource and invalidates every handle
from that world.
Destroying a world destroys every transient resource and invalidates every
handle from that world. A separate in-place reset operation is not part of the
Phase 1 contract.

## 7. Stepping and state

Expand All @@ -120,6 +123,14 @@ State retrieval has two paths:
Changed-body extraction returns neutral body handles and physical state. It
does not write a USD stage or a Stage Runner runtime world.

Phase 1 extraction is deterministic: each body appears at most once, results
are ordered by ascending opaque handle value, and taking the results drains the
queue. Creation is represented by the descriptor and direct initial state, not
by the changed queue. A successful command becomes observable through changed
state after stepping; destruction removes pending state for that body. Sleep,
wake, and teleport operations are not in the Phase 1 API and must define their
queue behavior when admitted.

## 8. Optional query capabilities

Queries are capability interfaces rather than mandatory methods on a
Expand Down Expand Up @@ -149,7 +160,7 @@ dimensions, or impossible descriptors are rejected consistently before
backend calls. Resource exhaustion and unsupported backend capabilities are
distinguishable from invalid input.

`RB-O1` has the following proposed mixed policy for Phase 1:
`RB-O1` uses the following mixed policy for Phase 1:

- value and descriptor validation throws `std::invalid_argument` before a
backend call;
Expand All @@ -167,8 +178,8 @@ distinguishable from invalid input.
typed `PhysicsError` carrying a solver-neutral `PhysicsErrorCode`.

This retains the proven Stage Runner call patterns while making backend
failures distinguishable. Phase 1 descriptor and world slices must test the
relevant branch before this proposal becomes accepted.
failures distinguishable. Descriptor and world contract tests cover the
Phase 1 branches; a concrete backend must retain the same outcomes.

## 10. Threading and ownership

Expand All @@ -184,13 +195,13 @@ contract. Broad additions require a consumer scenario and tests.

## 12. Open questions

- **RB-O1 (proposed resolution):** use the mixed policy in §9; accept it only
with the descriptor and world contract tests.
- **RB-O1 (resolved for Phase 1):** use the tested mixed policy in §9.
- **RB-O2 (resolved for Phase 1):** minimal vector, rotation, and transform
values live in `physicsCore`; a separate package requires an independent
consumer and an architecture revision.
- **RB-O3 (resolved for Phase 1):** use the 64-bit `categories` and
`collidesWith` sets defined in §5.2. Backend layer assignment is private and
may cache distinct filter combinations without changing this contract.
- **RB-O4:** semantics and ordering of changed-body extraction across create,
sleep, wake, teleport, and destroy.
- **RB-O4 (resolved for Phase 1):** use the ordering and drain semantics in
§7. Sleep, wake, and teleport remain outside the current API and must extend
this rule explicitly when admitted.
18 changes: 9 additions & 9 deletions docs/reference/CAPABILITY_MATRIX.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ capability on this page.
> installable `physicsCore` and `physicsJolt` package boundaries exist.
> `physicsCore` provides neutral rigid-transform values, typed handles, and
> validated box/body/fixed-constraint descriptors with semantic collision
> filters, but no world contract exists yet. No solver backend or OpenUSD
> plugin exists.
> filters plus a single-owner world contract. Optional queries, a solver
> backend, and an OpenUSD plugin do not exist yet.

## 1. Status vocabulary

Expand Down Expand Up @@ -39,16 +39,16 @@ capability on this page.

| Capability | Status | Evidence / note |
| --- | --- | --- |
| `physicsCore` package | partial | Installable `physicsCore::physicsCore` provides version, value, handle, and descriptor surfaces; the runtime contract remains Phase 1 |
| `physicsCore` package | partial | Installable `physicsCore::physicsCore` provides version, value, handle, descriptor, error, and world surfaces; optional queries remain Phase 1 |
| Neutral vector, quaternion, and transform values | supported | `physicsCore.values_handles` and the installed-consumer test cover the public headers and identity defaults |
| Opaque shape/body/constraint handles | supported | [`physics_core_values_handles_test.cpp`](../../libs/physicsCore/tests/physics_core_values_handles_test.cpp) covers invalid zero, typed identity, comparison, hashing, and representation size |
| Shape descriptors | supported | [`physics_core_descriptors_test.cpp`](../../libs/physicsCore/tests/physics_core_descriptors_test.cpp) covers the validated box descriptor; sphere/capsule remain Phase 4 |
| Static and dynamic body descriptors | supported | [`physics_core_descriptors_test.cpp`](../../libs/physicsCore/tests/physics_core_descriptors_test.cpp) covers shape identity, motion type, rigid transform, mass, and collision filter validation; no body lifecycle exists yet |
| Fixed-constraint descriptors | supported | [`physics_core_descriptors_test.cpp`](../../libs/physicsCore/tests/physics_core_descriptors_test.cpp) covers two distinct valid body handles; no constraint lifecycle exists yet |
| Force and velocity operations | planned | No implementation |
| Fixed-step world | planned | No implementation |
| Direct body state | planned | No implementation |
| Changed-body extraction | planned | No implementation |
| Static and dynamic body descriptors | supported | [`physics_core_descriptors_test.cpp`](../../libs/physicsCore/tests/physics_core_descriptors_test.cpp) covers shape identity, motion type, rigid transform, mass, and collision filter validation; lifecycle is covered by the partial world contract below, while no solver backend exists yet |
| Fixed-constraint descriptors | supported | [`physics_core_descriptors_test.cpp`](../../libs/physicsCore/tests/physics_core_descriptors_test.cpp) covers two distinct valid body handles; lifecycle is covered by the partial world contract below, while no solver backend exists yet |
| Force and velocity operations | partial | [`physics_core_world_test.cpp`](../../libs/physicsCore/tests/physics_core_world_test.cpp) covers the public command contract, validation, and dynamic/static/stale/cross-world outcomes through a deterministic contract world; no solver backend exists |
| Fixed-step world | partial | [`physics_core_world_test.cpp`](../../libs/physicsCore/tests/physics_core_world_test.cpp) covers the single-owner lifecycle interface and finite positive step validation; no solver backend exists |
| Direct body state | partial | [`physics_core_world_test.cpp`](../../libs/physicsCore/tests/physics_core_world_test.cpp) covers neutral state and unknown/stale/cross-world errors through the contract world; no solver backend exists |
| Changed-body extraction | partial | [`physics_core_world_test.cpp`](../../libs/physicsCore/tests/physics_core_world_test.cpp) covers unique handle ordering, drain behavior, creation exclusion, and destruction cleanup through the contract world; sleep, wake, and teleport are outside the Phase 1 API |
| Segment query capability | planned | No implementation |
| Ground query capability | planned | No implementation |
| Ray or shape-cast capabilities | planned | Later consumer-driven addition |
Expand Down
2 changes: 1 addition & 1 deletion docs/roadmap/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ status and ordering.

| Phase | Status | Current outcome |
| --- | --- | --- |
| 1 — extract `physicsCore` | in progress | Neutral values, typed handles, validated descriptors, and semantic collision filters are implemented; world lifecycle is next. |
| 1 — extract `physicsCore` | in progress | Neutral values, typed handles, validated descriptors, semantic collision filters, and the world contract are implemented; optional queries are next. |
| 2 — extract `physicsJolt` | not started | Waits for Phase 1 and an accepted Jolt dependency. |
| 3 — Stage Runner migration | not started | Waits for installable Phase 1–2 packages. |
| 4 — `physicsUsd` foundation | not started | Waits for the neutral rigid-body contract. |
Expand Down
20 changes: 9 additions & 11 deletions docs/roadmap/current.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

> **Status: Phase 1 in progress, 2026-09-22.** Phase 0 closed with successful
> hosted graph, Linux, and Windows cells. Neutral values, typed handles, and
> validated descriptors are the implemented extraction slices.
> validated descriptors plus the world lifecycle/state contract are the
> implemented extraction slices.

## 1. Outcome

Expand Down Expand Up @@ -32,19 +33,17 @@ values, handles, and descriptors
backend layer identifier enters the public contract.
- `physicsCore.values_handles`, `physicsCore.descriptors`, and the clean-prefix
installed consumer cover these public slices.
- `RB-O1` has a proposed mixed error policy in the
[rigid-body contract](../design/RIGID_BODY_CONTRACT.md#9-errors-and-validation).
- `physicsCore.world` covers fixed-step/vector validation, explicit resource
lifecycle, commands, direct state, deterministic changed-state draining,
stale and cross-world handle behavior, and typed backend errors.
- `RB-O1` is resolved by the tested mixed error policy in the
[rigid-body contract](../design/RIGID_BODY_CONTRACT.md#9-errors-and-validation),
and the Phase 1 portion of `RB-O4` fixes changed-state drain ordering.
- `RB-O3` is resolved by the semantic category/mask contract in
[the body descriptor](../design/RIGID_BODY_CONTRACT.md#52-bodies).

## 3. Remaining Phase 1 work

- Implement and test fixed-step validation; use the world tests to accept or
revise the remaining `RB-O1` branches.
- Extract the single-owner world lifecycle, force/velocity commands, direct
state, fixed stepping, and changed-state draining contract.
- Settle `RB-O4` changed-state ordering across create, sleep, wake, teleport,
and destroy before the world contract is accepted.
- Extract optional segment and ground query capabilities with ignored-body and
support-contact behavior.
- Keep `PhysicsRuntime`, prim identity, dirty synchronization, and Stage
Expand All @@ -57,6 +56,5 @@ values, handles, and descriptors
- `physicsCore` public headers and link interfaces contain no OpenUSD, Jolt,
Stage Runner, MMD, or VRM dependency.
- A clean-prefix consumer includes and exercises the runtime contract.
- `RB-O1` and the Phase 1 portion of `RB-O4` are accepted or narrowed to
explicitly deferred behavior; the accepted `RB-O3` filter remains covered.
- The accepted `RB-O1`, `RB-O3`, and Phase 1 `RB-O4` behavior remains covered.
- The capability matrix and package contract describe only the tested surface.
2 changes: 2 additions & 0 deletions libs/physicsCore/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ endif()

add_library(physicsCore STATIC
src/descriptors.cpp
src/errors.cpp
src/world.cpp
src/version.cpp)
add_library(physicsCore::physicsCore ALIAS physicsCore)
set_target_properties(physicsCore PROPERTIES
Expand Down
24 changes: 24 additions & 0 deletions libs/physicsCore/include/usd_physics/core/errors.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#pragma once

#include <stdexcept>
#include <string>

namespace usd_physics::core {

enum class PhysicsErrorCode {
backendUnavailable,
resourceExhausted,
solverFailure,
};

class PhysicsError : public std::runtime_error {
public:
PhysicsError(PhysicsErrorCode code, const std::string& message);

[[nodiscard]] PhysicsErrorCode code() const noexcept { return code_; }

private:
PhysicsErrorCode code_;
};

} // namespace usd_physics::core
47 changes: 47 additions & 0 deletions libs/physicsCore/include/usd_physics/core/world.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#pragma once

#include "usd_physics/core/descriptors.h"

#include <chrono>
#include <vector>

namespace usd_physics::core {

struct BodyState {
BodyHandle body;
Transform transform;
Vector3 linearVelocity;
};

class PhysicsWorld {
public:
using Duration = std::chrono::duration<double>;

PhysicsWorld() = default;
virtual ~PhysicsWorld();
PhysicsWorld(const PhysicsWorld&) = delete;
PhysicsWorld& operator=(const PhysicsWorld&) = delete;
PhysicsWorld(PhysicsWorld&&) = delete;
PhysicsWorld& operator=(PhysicsWorld&&) = delete;

virtual ShapeHandle createShape(const ShapeDescriptor& descriptor) = 0;
virtual bool destroyShape(ShapeHandle shape) noexcept = 0;

virtual BodyHandle createBody(const BodyDescriptor& descriptor) = 0;
virtual bool destroyBody(BodyHandle body) noexcept = 0;

virtual ConstraintHandle createConstraint(const ConstraintDescriptor& descriptor) = 0;
virtual bool destroyConstraint(ConstraintHandle constraint) noexcept = 0;

virtual bool applyForce(BodyHandle body, Vector3 force) = 0;
virtual bool setLinearVelocity(BodyHandle body, Vector3 velocity) = 0;
[[nodiscard]] virtual BodyState bodyState(BodyHandle body) const = 0;

virtual void step(Duration fixedStep) = 0;
virtual std::vector<BodyState> takeChangedBodyStates() = 0;
};

void validatePhysicsStep(PhysicsWorld::Duration fixedStep);
void validatePhysicsVector(Vector3 vector, const char* name);

} // namespace usd_physics::core
8 changes: 8 additions & 0 deletions libs/physicsCore/src/errors.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include "usd_physics/core/errors.h"

namespace usd_physics::core {

PhysicsError::PhysicsError(PhysicsErrorCode code, const std::string& message)
: std::runtime_error(message), code_(code) {}

} // namespace usd_physics::core
Loading
Loading