Skip to content

Derive USD cable joint stiffness from local segment lengths - #3730

Open
jumyungc wants to merge 4 commits into
newton-physics:mainfrom
jumyungc:jumyungc/fix-cable-local-stiffness
Open

Derive USD cable joint stiffness from local segment lengths#3730
jumyungc wants to merge 4 commits into
newton-physics:mainfrom
jumyungc:jumyungc/fix-cable-local-stiffness

Conversation

@jumyungc

@jumyungc jumyungc commented Jul 30, 2026

Copy link
Copy Markdown
Member

Description

The experimental USD deformable importer converted cable material moduli to joint stiffness using terms like E*A/L and E*I/L, but passed a single curve-wide mean segment length as L to add_rod() / add_rod_graph(), which broadcast it to every joint. A material constant therefore produced different physical stiffness depending only on how evenly the curve happened
to be sampled. The welded-graph path had the same behavior. Each joint now uses its own dual rest length, 0.5 * (L_parent + L_child) — the series compliance of the two segment halves it connects. Uniformly sampled cables are unchanged.

Closes #3722.

Checklist

  • New or existing tests cover these changes
  • The documentation is up to date with these changes
  • CHANGELOG.md has been updated (if user-facing change)

Test plan

Bug fix

Steps to reproduce:

Minimal reproduction:

import newton

# Code that demonstrates the bug

New feature / API change

import newton

# Code that demonstrates the new capability

Summary by CodeRabbit

  • New Features

    • Added cubic and triplanar texture projection for UV-less shapes.
    • USD imports now preserve textures when recoverable UVs are unavailable.
    • Textured meshes and material subsets use white base colors to prevent unintended tinting.
  • Changed

    • USD deformable cable imports now calculate joint stiffness using local rest lengths of adjacent segments.
    • Authored rest-shape points are used for stiffness conversion when available, while current points define the relaxed pose.
  • Documentation

    • Updated USD importer documentation to describe local stiffness normalization and rest-shape behavior.

Signed-off-by: JC Chang <jumyungc@nvidia.com>
@jumyungc jumyungc added this to the 1.5 Release milestone Jul 30, 2026
@jumyungc jumyungc self-assigned this Jul 30, 2026
@jumyungc
jumyungc marked this pull request as draft July 30, 2026 12:03
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

USD deformable cable imports now derive stretch, shear, bend, and twist stiffness per joint from adjacent rest-segment lengths. The builder applies joint targets after rod construction, with tests and documentation covering graded cables and authored rest shapes.

Changes

USD cable stiffness

Layer / File(s) Summary
Joint stiffness update contract
newton/_src/sim/builder.py
Adds a helper that writes per-DOF cable stiffness and recomputes target modes from stiffness and damping gains.
Local stiffness import wiring
newton/_src/utils/import_usd_deformable_cable.py
Uses local dual rest lengths for standalone cables and welded graphs, including authored rest-shape handling and edge validation.
Behavior validation and documentation
newton/tests/test_import_usd_deformable_cable.py, docs/concepts/usd_parsing.rst, CHANGELOG.md
Tests cover graded, periodic, zero-stiffness, and rest-shape cases; documentation describes local normalization.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant USDImporter
  participant ModelBuilder
  participant CableJointTargets
  USDImporter->>ModelBuilder: construct rod or rod-graph joints
  USDImporter->>USDImporter: compute adjacent rest-segment dual lengths
  USDImporter->>ModelBuilder: apply material stiffness per joint
  ModelBuilder->>CableJointTargets: update joint_target_ke and joint_target_mode
Loading

Possibly related issues

  • Issue 3485: Concerns USD cable import stiffness handling across stretch, shear, bend, and twist joints.

Possibly related PRs

Suggested reviewers: adenzler-nvidia, mzamoramora-nvidia

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes deriving USD cable joint stiffness from local segment lengths, matching the primary change.
Linked Issues check ✅ Passed The importer now derives per-joint stiffness from local dual rest lengths for rod and welded paths, with tests covering graded and uniform sampling [#3722].
Out of Scope Changes check ✅ Passed The code, tests, documentation, and changelog changes directly support the cable stiffness import fix and introduce no unrelated scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jul 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@jumyungc
jumyungc marked this pull request as ready for review July 30, 2026 23:47

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
newton/tests/test_import_usd_deformable_cable.py (1)

309-311: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Shorten the periodic-case comment.

This comment is useful, but it can be reduced to the non-obvious detail—the closing joint pairs the final and first segment lengths.

Suggested wording
-            # A 3-4-5 triangle. add_rod appends the loop-closing joint last, and its dual length
-            # pairs the last and first segments (0.5 and 0.3) -- the only joint whose two operands
-            # are not neighbors in the body list.
+            # The closing joint is appended last and pairs the 0.5 and 0.3 segments.

As per path instructions, inline Python comments should be brief and explain why non-obvious code exists.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@newton/tests/test_import_usd_deformable_cable.py` around lines 309 - 311,
Shorten the inline comment in test_import_usd_deformable_cable.py to retain only
the non-obvious behavior: the loop-closing joint pairs the final and first
segment lengths. Remove the triangle explanation and other implementation
details.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@newton/tests/test_import_usd_deformable_cable.py`:
- Around line 309-311: Shorten the inline comment in
test_import_usd_deformable_cable.py to retain only the non-obvious behavior: the
loop-closing joint pairs the final and first segment lengths. Remove the
triangle explanation and other implementation details.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro Plus

Run ID: bd4e4a23-bae6-4698-b49c-d7b662b0455d

📥 Commits

Reviewing files that changed from the base of the PR and between c1b047f and ef468d0.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • docs/concepts/usd_parsing.rst
  • newton/_src/utils/import_usd_deformable_cable.py
  • newton/tests/test_import_usd_deformable_cable.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • docs/concepts/usd_parsing.rst
  • newton/_src/utils/import_usd_deformable_cable.py

@jumyungc
jumyungc requested a review from andrewkaufman July 30, 2026 23:50
@andrewkaufman

Copy link
Copy Markdown
Member

I haven't really reviewed this yet, but it would be good to account for the moduli->stiffness change being added to the proposal as well, @sschirm for details.

@jumyungc

Copy link
Copy Markdown
Member Author

I haven't really reviewed this yet, but it would be good to account for the moduli->stiffness change being added to the proposal as well, @sschirm for details.

Thanks for the heads-up! If it lands while this PR is open, I’ll update this PR accordingly.

@mzamoramora-nvidia

Copy link
Copy Markdown
Member

Thanks for addressing the mean-length normalization and for covering graded, periodic, welded, zero-stiffness, and standalone rest-shape cases. I ran the relevant tests locally; the PR selection passed, and the strengthened tests fail against the unfixed base as expected.

I have one related request: now that the welded graph can receive per-joint stiffness, could it also retain authored restShapePoints for each owning curve for per-edge normalization? The current standalone and welded paths otherwise assign different stiffness to equivalent authored rest geometry. I left an inline suggestion with a possible implementation and regression-test direction.

I am reviewing the USD material attributes according to the proposal semantics implemented by Newton today. I would not block this PR while waiting for the possible proposal revision mentioned in the discussion.

# rather than changing the curve's behavior silently (a single, unwelded curve honors both).
for key in comp_paths:
kprim = curve_recs[key].prim
if deformable_read(kprim, "restShapePoints") is not None:

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.

Would it be possible to preserve authored restShapePoints for welded cable graphs as part of this PR?

The previous warning made sense while add_rod_graph() could only receive one scalar stiffness, but this PR removes that limitation by applying stiffness per joint after construction. The graph also retains the owning curve and segment index for each edge in edge_owner, so it seems possible to compute a rest length for each edge from the transformed restShapePoints of that curve, while continuing to use the current points for node_positions and the constructed pose.

As written, an equivalent cable gets different normalization depending on whether it is imported standalone or as part of a welded graph: the standalone path uses authored rest lengths, while the welded path drops them and uses the possibly deformed current lengths. Could we pass those per-edge rest lengths to _apply_local_cable_stiffnesses() and replace test_welded_graph_drops_rest_shape_warns with a graded welded-rest-shape regression?

return stretch, shear, bend, twist


def _apply_local_cable_stiffnesses(

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.

Small simplification: this helper only reads ctx.builder from the import context. Would passing builder: ModelBuilder directly make the dependency clearer and keep the stiffness calculation independent of the larger import context?

@jumyungc jumyungc removed this from the 1.5 Release milestone Jul 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

[BUG] Cable import derives per-joint stiffness from the mean segment length

3 participants