Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
720d3e3
Honor applied USD schema fallbacks
adenzler-nvidia Jul 20, 2026
f01a02a
Keep composed resolution internal
adenzler-nvidia Jul 20, 2026
2cd7321
Centralize schema fallback compatibility
adenzler-nvidia Jul 20, 2026
2e00533
Preserve custom resolver compatibility
adenzler-nvidia Jul 20, 2026
8193dae
Harden schema fallback migration audit
adenzler-nvidia Jul 20, 2026
ad2236d
Expose applied schema fallback opt-in
adenzler-nvidia Jul 20, 2026
b3559ea
Preserve explicit fallback policy choices
adenzler-nvidia Jul 20, 2026
165eebd
Default fallback migration to legacy
adenzler-nvidia Jul 20, 2026
6976d1f
Merge remote-tracking branch 'upstream/main' into adenzler/composed-s…
adenzler-nvidia Jul 20, 2026
61759ff
Simplify schema fallback migration
adenzler-nvidia Jul 20, 2026
0a6a976
Fix composed PhysX schema fallbacks
adenzler-nvidia Jul 20, 2026
3adf7a5
Compare schema migrations after normalization
adenzler-nvidia Jul 23, 2026
29adc0c
Merge upstream/main into schema fallback work
adenzler-nvidia Jul 23, 2026
96b10e8
Rely on strict warnings in schema tests
adenzler-nvidia Jul 23, 2026
a098402
Merge remote-tracking branch 'upstream/main' into adenzler/composed-s…
adenzler-nvidia Jul 23, 2026
d8f5dd6
Use registered USD schema fallbacks
adenzler-nvidia Jul 23, 2026
0fd6e1a
Add source-neutral USD schema resolution
adenzler-nvidia Jul 17, 2026
2c15110
Harden schema resolution facade
adenzler-nvidia Jul 20, 2026
1ecec55
Document PhysX D6 limit correction
adenzler-nvidia Jul 20, 2026
eaaac62
Generalize schema resolution design
adenzler-nvidia Jul 20, 2026
90e996d
Unify schema resolution entry points
adenzler-nvidia Jul 20, 2026
7cbc52a
Preserve explicit null resolver defaults
adenzler-nvidia Jul 20, 2026
5baabff
Keep schema fallbacks source-owned
adenzler-nvidia Jul 23, 2026
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
- Add opt-in filtering of static-static, static-kinematic, and kinematic-kinematic contacts during broad-phase collision detection. Set `CollisionPipeline(include_static_kinematic_pairs=False)` to enable filtering; the default preserves existing contact generation. `Model.shape_contact_pairs` remains an unfiltered superset for direct consumers such as `SolverKamino` and hydroelastic SDF setup.
- Add opt-in `body_frame_origin="com"` to `ModelBuilder.add_rod()` and `ModelBuilder.add_rod_graph()` for COM-centered cable capsule body frames.
- Add `sign_method` argument to `Mesh.build_sdf` and `SDF.create_from_mesh` support for a `"normal"` (angle-weighted pseudo-normal) sign strategy, for selecting the inside/outside sign of the baked SDF (`"auto"`, `"parity"`, `"winding"`, or `"normal"`).
- Add source-neutral USD schema resolution through `newton.usd.SchemaResolution` and `ModelBuilder.add_usd(schema_resolution=...)`, allowing populated scene adapters to reuse Newton's precedence and conversions with adapter-supplied registered schema fallbacks.
- Add `forward_depth_image` output support to `SensorTiledCamera.update()` and `SensorTiledCamera.utils.create_forward_depth_image_output()` for native forward-depth rendering without post-processing `depth_image`.
- Add optional `shear_stiffness`/`shear_damping` and `twist_stiffness`/`twist_damping` controls to `ModelBuilder.add_joint_cable()`, `ModelBuilder.add_rod()`, and `ModelBuilder.add_rod_graph()`; omitted shear defaults to stretch and omitted twist defaults to bend for compatibility.
- Add `newton.utils.CableStiffness` and extend `newton.utils.create_cable_stiffness_from_elastic_moduli()` with `poissons_ratio`/`shear_modulus` inputs that include torsional `GJ/L` stiffness.
Expand All @@ -36,6 +37,8 @@

### Changed

- Detect applied but unauthored USD schema properties whose registered fallbacks will change resolver results in a future release, while retaining the current values during the compatibility period; pass ``use_applied_schema_fallbacks=True`` to opt into the future behavior.

- Compile tiled camera render kernels with CUDA fast math by default for faster rendering; set `SensorTiledCamera.render_config.enable_fast_math = False` for bit-exact, IEEE-precise output.
- Optimize raycast/raytrace queries by restructuring ray-shape intersection into local-space primitives and compile specialized depth/shadow variants that skip unused surface-normal work (mesh shadows also use any-hit queries).
- Change experimental `SolverVBD` cable constraint slots from `[STRETCH=0, BEND=1]` to `[STRETCH=0, SHEAR=1, BEND=2, TWIST=3]`, allowing each stiffness and constraint mode to be configured independently. Existing cable calls using raw `slot=1` or `JointSlot.ANGULAR` now select shear; use `JointSlot.BEND` (now slot 2) to select bending.
Expand Down
1 change: 1 addition & 0 deletions docs/api/newton_usd.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ resolver types used by :meth:`newton.ModelBuilder.add_usd`.
:nosignatures:

PrimType
SchemaResolution
SchemaResolver
SchemaResolverMjc
SchemaResolverNewton
Expand Down
19 changes: 17 additions & 2 deletions docs/concepts/usd_parsing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,8 @@ Schema resolvers bridge the gap between solver-specific USD schemas and Newton's

.. experimental::

The ``schema_resolvers`` argument in :meth:`newton.ModelBuilder.add_usd` may change without prior notice.
The ``schema_resolvers`` and ``schema_resolution`` arguments in
:meth:`newton.ModelBuilder.add_usd` may change without prior notice.

Solver Attribute Remapping
~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -474,7 +475,21 @@ The attribute resolution process follows a three-layer fallback hierarchy to det

1. **Authored Values**: Resolvers are queried in priority order; the first resolver that finds an authored value on the prim returns it and remaining resolvers are not consulted.
2. **Importer Defaults**: If no authored value is found, Newton's importer uses a property-specific fallback (e.g. ``builder.default_joint_cfg.armature`` for joint armature). This takes precedence over schema-level defaults.
3. **Approximated Schema Defaults**: If neither an authored value nor an importer default is available, Newton falls back to a hardcoded approximation of each solver's schema default, defined in Newton's resolver mapping. These approximations will be replaced by actual USD schema defaults in a future release.
3. **Resolver Compatibility Defaults**: If neither an authored value nor an importer default is available, Newton falls back to the resolver mapping's compatibility default.

This order is retained during a compatibility period. In the future, applying a
schema will give it ownership of its properties: an unauthored property will use
the fallback from its registered USD schema definition before a lower-priority
resolver or importer default. Newton does not treat resolver compatibility
defaults as schema-declared fallbacks; the relevant codeless or code-generated
schema plugin must be registered with USD for first-class fallback ownership.
Unregistered schemas retain their resolver compatibility defaults after
importer defaults as a second-class path. Newton emits a
:class:`DeprecationWarning` when the future rule would select a different
resolver value or source. Author the intended property value explicitly to
preserve it across the transition, or pass
``use_applied_schema_fallbacks=True`` to adopt the future behavior now without
migration warnings.

**Configuring Resolver Priority:**

Expand Down
273 changes: 273 additions & 0 deletions docs/design/schema-resolution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
<!-- SPDX-FileCopyrightText: Copyright (c) 2026 The Newton Developers -->
<!-- SPDX-License-Identifier: CC-BY-4.0 -->

# Source-neutral USD schema resolution

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file will be removed for the final version, but it motivates the design for now so I think it's useful to have it in the PR.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we just migrate this doc to an Issue that the PR implements?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to keep it up-to-date while the PR evolves, once final I will move the design to the PR description.

Status: design proposal

## Summary

Newton's schema resolvers currently read `Usd.Prim` objects, transform raw
attributes, choose between configured schemas, and provide mapping defaults.
Some source-sensitive precedence remains in `import_usd.py`. This couples the
resolution policy to the PXR importer and prevents scene representations that
do not expose PXR prims from reusing the same behavior.

This proposal separates attribute access from scalar resolution while keeping
the current `ModelBuilder.add_usd()` construction path and behavior. One typed
`SchemaResolution` object configures both PXR and non-PXR consumers; the
existing `schema_resolvers=` argument constructs that object internally.
Applied schema identity is part of the input: an applied schema owns the
properties it defines, including its USD fallbacks. Resolver definitions
identify ownership and conversion. The source adapter supplies registered
schema fallbacks: the PXR adapter reads them from `Usd.SchemaRegistry`, while a
PXR-free adapter provides the equivalent versioned schema metadata explicitly.
Batched resolution, Warp functions, and direct ModelBuilder buffer population
are deliberately deferred.

## Goals

- Keep core Newton as the single owner of schema precedence and conversion.
- Preserve the behavior of `add_usd()` and `schema_resolvers=` by default.
- Resolve values and applied schemas supplied without a `Usd.Prim`.
- Read fallbacks from registered USD schemas on the PXR path.
- Accept registered schema fallbacks from schema-neutral source adapters.
- Keep schema metadata versioning in the adapter that owns the scene source.
- Keep the external mechanism small and hide candidates, provenance, and storage.
- Make the scalar contract suitable for later columnar and Warp execution.
- Let non-PXR scene consumers reuse the resolver without changing their
construction loops.

## Non-goals

- Changing canonical USDPhysics discovery, topology, or geometry parsing.
- Replacing `ModelBuilder.add_*()` with direct array construction.
- Defining an external scene representation or public batch API.
- Making arbitrary downstream resolver definitions device-capable.
- Introducing a scene intermediate representation.

## Current behavior

Before this change, `SchemaResolverManager.get_value()` applied this order:

1. The first authored value in resolver priority order.
2. The caller-provided importer default, when non-`None`.
3. The first non-`None` mapping default in resolver priority order.
4. `None`.

That makes an unapplied schema contribute defaults and lets an importer default
override the fallback of an applied schema. It also disagrees with specialized
paths such as MuJoCo joint-limit resolution.

The composed order is evaluated per resolver, in priority order:

1. Use a source value when present.
2. If the schema owning the property is applied, use its USD fallback and stop.
3. Otherwise continue to the next resolver.
4. Use the caller default only when no resolver owns the property.

Typed schemas participate like applied API schemas. During migration, a private
policy computes this result but returns the legacy value. If the results differ,
the public entry points emit a `DeprecationWarning`. The policy is shared by PXR
and mapping sources and is not user-selectable. A later release changes one
private default to return the composed result; the legacy branch can then be
removed after its deprecation window. Unowned entries retain their mapping
defaults. A schema fallback may itself be an engine-default sentinel; using the
builder in response to that sentinel is still schema-defined behavior.

## Proposed boundary

The resolver engine consumes source values and schema identity:

```text
read(attribute_name) -> value or missing
schemas -> applied API and typed schema names
fallback(schema_name, attribute_name) -> raw USD value or missing
```

The PXR adapter reads authored values and applied/type metadata, then asks
`Usd.SchemaRegistry` for the composed prim definition and its attribute
fallbacks. A non-PXR source provides already-composed values, recorded schema
identity, and the fallbacks for schemas it treats as registered. Resolver
priority, transformations, and selected-source provenance are shared.

Schemas without authoritative metadata remain a second-class compatibility
path. Their authored values still participate in resolver priority, while
importer defaults precede resolver compatibility defaults. They do not claim
registered-schema fallback ownership.

Canonical USDPhysics descriptors remain importer inputs. Resolvers only supply
extension-schema properties such as armature, friction, contact parameters,
initial joint state, and Newton-specific collision configuration.

## Compatibility strategy

The existing public classes and methods remain valid:

- `SchemaResolver` and its built-in subclasses.
- `SchemaResolver.get_value(prim, ...)`.
- `ModelBuilder.add_usd(..., schema_resolvers=...)`.

`SchemaResolution` is the common setup object:

```python
resolution = newton.usd.SchemaResolution(
resolvers,
)
builder.add_usd(stage, schema_resolution=resolution)
```

`schema_resolvers` and `schema_resolution` are mutually exclusive. The former
is a compatibility shorthand for constructing `SchemaResolution(resolvers)`;
it does not select another engine or fallback policy. After consumers have had
time to migrate to a reusable object, the shorthand can be deprecated and then
removed without changing resolution semantics.

Built-in composite getters are migrated to the source-neutral reader. The
existing `usd_value_getter` callback remains supported for downstream resolver
subclasses on the PXR adapter. Attempting to use such a resolver with mapping
inputs raises an actionable error rather than silently changing behavior.

The same object resolves mapping inputs directly:

```python
resolution = newton.usd.SchemaResolution(
resolvers,
)
requirements = resolution.requirements(PrimType.JOINT)
schemas = resolution.schemas(PrimType.JOINT)
properties = resolution.resolve(
PrimType.JOINT,
values,
schemas=applied_schemas,
# Registered schema metadata supplied by this source adapter.
schema_fallbacks={
"ExampleJointAPI": {"example:armature": 0.0},
},
defaults={"armature": builder.default_joint_cfg.armature},
)
```

Fallback tables contain raw USD values; the common resolver applies the same
composite getter and value transformer as it does to authored values. These
methods accept an optional `keys=` selection so an integration can request only
the logical properties it can preserve.

`SchemaResolution` is public and typed; its internals are not. Candidate types,
provenance, mapping definitions, transforms, diagnostics, compatibility policy,
and future Warp storage remain private. `requirements()` returns source
attribute names, `schemas()` returns the schema identities needed for
ownership, and `resolve()` returns canonical logical keys and values. This
scalar mapping interface is intended for the existing `ModelBuilder.add_*()`
path, not the future hot path.

## `add_usd()` migration

`ModelBuilder.add_usd()` always delegates priority and fallback resolution to a
`SchemaResolution` through the PXR adapter. It constructs a default Newton
resolution when neither argument is supplied and wraps `schema_resolvers=` when
that shorthand is used. The adapter caches composed schema fallbacks by prim
type and schema. `Usd.SchemaRegistry` remains authoritative on this path;
`schema_fallbacks` is input for source-neutral `resolve()` calls. Attribute
collection for the returned `schema_attrs` dictionary remains separate and
unchanged.

The first implementation does not move every higher-level rule out of
`import_usd.py`. Source-specific branches such as MuJoCo raw-limit provenance,
material-versus-shape contact precedence, and legacy margin handling migrate in
small behavior-preserving changes after the common scalar engine is established.

## Non-PXR source integration

A schema-aware scene source supplies attribute values plus typed and applied
schema identities to the same `SchemaResolution` inside its existing body,
shape, and joint loops. It also supplies the registered fallbacks for the
schema versions its transport exposes. Topology discovery, ordering, and
`ModelBuilder.add_*()` calls remain source concerns. Equivalent local
precedence and conversion code can be removed as each entity family moves to
the shared engine.

A non-PXR source must preserve the USD fallback semantics expected by the
resolver. A source that substitutes an engine descriptor default for a USD
fallback cannot provide exact parity for that property without provenance or a
source-contract change. Any temporary value normalization belongs in the source
adapter and must document the ambiguous explicitly-authored value.

This is intentionally scalar. It establishes semantic parity before optimizing
data movement.

## Future batch execution

A later design may bind `requirements()` to aligned source columns and execute
one kernel per entity family. Built-in transforms can then be represented by
internal operation identifiers with Python and `wp.func` implementations.
ModelBuilder must first provide reserved numeric destination ranges; otherwise
device results would be converted back into Python lists.

No batch types or Warp implementation details are part of the initial public
contract.

## Diagnostics

The scalar path preserves existing Python warnings. A future device path cannot
emit warnings from a `wp.func`; it will return internal diagnostic bits for the
host to report after execution. Diagnostic representation is not public.

## Testing

- Existing schema resolver and `add_usd()` APIs remain valid.
- Tests cover absent schemas, applied-but-unauthored fallbacks, authored zero,
authored nonzero, resolver ordering, transformations, and missing values.
- The same values and schema identity resolve equally through PXR and mapping
sources.
- Adapter-supplied fallbacks establish registered ownership without importing
PXR.
- Registered Newton schema fallbacks are read directly from the PXR registry.
- Legacy PXR-only callbacks continue to work and fail explicitly through the
source-neutral facade.
- Later cross-source tests compare final builder/model fields against
`add_usd()` for the same asset.

## Alternatives

### Duplicate mappings in each scene integration

This keeps the implementations independent but guarantees semantic drift and
duplicates every future schema fix.

### Construct temporary USD prims in non-PXR integrations

This retains the current resolver but restores the PXR dependency and defeats
the source-neutral boundary.

### Standardize a scene IR first

An IR would combine schema resolution, topology, and construction concerns.
The scalar source boundary is sufficient for reuse and does not constrain a
future bulk ModelBuilder design.

### Expose candidate and Warp structures publicly

This would freeze implementation details before the column and builder storage
contracts exist. The narrow typed facade leaves those choices open.

## Rollout

1. Introduce the typed setup object and shared scalar engine.
2. Route both `add_usd()` arguments through that object while retaining legacy
outputs behind one private compatibility policy.
3. Declare property ownership and audit applied-schema fallback differences for
both PXR and mapping sources.
4. Flip the private policy after the deprecation window, then remove the legacy
branch and eventually the `schema_resolvers=` shorthand.
5. Move higher-level `add_usd()` resolver policy into shared entity helpers.
6. Adopt those helpers incrementally in non-PXR scene integrations.
7. Design batch column binding and ModelBuilder reservation separately.

## Open questions

- Whether downstream custom resolver authoring should remain supported publicly.
- Which higher-level importer rules belong in entity resolvers versus canonical
USDPhysics lowering.
- Whether the eventual batch entry point belongs to `newton.usd` or
`ModelBuilder`.
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ Newton Physics

FAQ <faq>
Migration Guide <migration>
Schema Resolution Design <design/schema-resolution>
Isaac Lab <lab/isaac-lab>


Expand Down
Loading
Loading