Skip to content

[3.0.0-beta2] Fix PhysX scene data for joint-labeled bodies#6148

Merged
ooctipus merged 1 commit into
isaac-sim:release/3.0.0-beta2from
ooctipus:zhengyuz/beta2-physx-scene-data-shadowhand
Jun 11, 2026
Merged

[3.0.0-beta2] Fix PhysX scene data for joint-labeled bodies#6148
ooctipus merged 1 commit into
isaac-sim:release/3.0.0-beta2from
ooctipus:zhengyuz/beta2-physx-scene-data-shadowhand

Conversation

@ooctipus

Copy link
Copy Markdown
Collaborator

Summary

  • Cherry-picks Fix PhysX scene data for joint-labeled bodies #6041 onto release/3.0.0-beta2.
  • Skips USD joint prims when building the global PhysX scene-data rigid-body view.
  • Resolves Newton visualization body labels that point at USD joints through their rigid-body targets.
  • Adds regression coverage for joint/body leaf-name collisions.

Validation

  • python3 -m py_compile source/isaaclab_newton/isaaclab_newton/physics/newton_manager.py source/isaaclab_physx/isaaclab_physx/physics/physx_manager.py source/isaaclab/test/sim/test_newton_manager_visualization_state.py source/isaaclab_physx/test/sim/test_physx_scene_data_backend.py
  • git diff --check upstream/release/3.0.0-beta2...HEAD
  • python3 tools/changelog/cli.py check release/3.0.0-beta2
  • pre-commit run --files source/isaaclab/changelog.d/zhengyuz-physx-scene-data-shadowhand.skip source/isaaclab/test/sim/test_newton_manager_visualization_state.py source/isaaclab_newton/changelog.d/zhengyuz-physx-scene-data-shadowhand.rst source/isaaclab_newton/isaaclab_newton/physics/newton_manager.py source/isaaclab_physx/changelog.d/zhengyuz-physx-scene-data-shadowhand.rst source/isaaclab_physx/isaaclab_physx/physics/physx_manager.py source/isaaclab_physx/test/sim/test_physx_scene_data_backend.py
  • Focused pytest attempted with python3 and ./isaaclab.sh -p; this local checkout did not have the needed runtime package setup, so the tests stopped at missing isaaclab_newton/toml imports before exercising the change.

@github-actions github-actions Bot added the isaac-lab Related to Isaac Lab team label Jun 11, 2026
@greptile-apps

greptile-apps Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR cherry-picks a fix from release/3.0.0-beta2 that addresses two related issues with PhysX scene data and Newton visualization when USD joint prims share leaf names with rigid bodies (the ShadowHand use case). A joint-skip guard is added to PhysxSceneDataBackend.get_rigid_body_view, and a new _resolve_scene_data_body_paths helper resolves Newton body labels that point at USD joints to their real rigid-body targets.

  • physx_manager.py: Joint prims (prim.IsA(UsdPhysics.Joint)) are now skipped before the RigidBodyAPI check during stage traversal, preventing ghost joint entries from polluting the PhysX tensor rigid-body view.
  • newton_manager.py: update_visualization_state now calls _resolve_scene_data_body_paths to remap any Newton body label that points at a joint prim to the joint's Body1Rel (falling back to Body0Rel) rigid-body target before building the scene-data mapping.
  • New regression tests cover both the physx-side joint skip and the Newton-side joint-to-body-path resolution.

Confidence Score: 4/5

The PhysX-side joint skip is safe and well-tested; the Newton-side resolver logic is correct, but the removal of the defensive body_label guard can crash update_visualization_state for any model where body_label is None.

The newton_manager.py change introduced a regression: the old call used getattr(cls._model, 'body_label', None) or [] to handle a missing or None attribute, and the new list(cls._model.body_label) strips that safety. Any model variant where body_label is None will raise TypeError at runtime inside update_visualization_state, breaking Newton visualization sync for those models.

source/isaaclab_newton/isaaclab_newton/physics/newton_manager.py — specifically line 1838 where the body_label guard was weakened.

Important Files Changed

Filename Overview
source/isaaclab_newton/isaaclab_newton/physics/newton_manager.py Adds _resolve_scene_data_body_paths; replaces defensive getattr/or-[] guard with direct body_label access, introducing a potential crash if body_label is None.
source/isaaclab_physx/isaaclab_physx/physics/physx_manager.py Adds joint-prim skip guard before RigidBodyAPI check; change is minimal, correct, and well-tested.
source/isaaclab_physx/test/sim/test_physx_scene_data_backend.py New test file validating that joint prims with RigidBodyAPI are excluded from the rigid-body view; follows module-level importorskip pattern correctly.
source/isaaclab/test/sim/test_newton_manager_visualization_state.py Adds a test for the new joint-to-body-path resolution; uses pytest.importorskip inside the function body (unusual pattern, but functionally correct).
source/isaaclab_newton/changelog.d/zhengyuz-physx-scene-data-shadowhand.rst Changelog entry for Newton side of the fix; clear and accurate description.
source/isaaclab_physx/changelog.d/zhengyuz-physx-scene-data-shadowhand.rst Changelog entry for PhysX side of the fix; clear and accurate description.
source/isaaclab/changelog.d/zhengyuz-physx-scene-data-shadowhand.skip Empty skip marker for the isaaclab package changelog; intentional.

Sequence Diagram

sequenceDiagram
    participant Consumer
    participant NewtonManager
    participant SceneDataProvider
    participant PhysxSceneDataBackend
    participant UsdStage

    Consumer->>NewtonManager: update_visualization_state()
    NewtonManager->>NewtonManager: _ensure_visualization_model()
    alt _scene_data_mapping is None
        NewtonManager->>NewtonManager: _resolve_scene_data_body_paths(body_label, stage)
        loop For each body path that is a USD joint
            NewtonManager->>UsdStage: GetPrimAtPath(body_path)
            UsdStage-->>NewtonManager: joint prim
            NewtonManager->>NewtonManager: _joint_body_path(prim)
            NewtonManager->>UsdStage: GetBody1Rel / GetBody0Rel targets
            UsdStage-->>NewtonManager: rigid-body target path
        end
        NewtonManager->>SceneDataProvider: create_mapping(resolved_body_paths)
        SceneDataProvider-->>NewtonManager: _scene_data_mapping
    end
    NewtonManager->>SceneDataProvider: get_transforms(_scene_data, mapping)
    SceneDataProvider->>PhysxSceneDataBackend: get_rigid_body_view()
    alt _rigid_body_view is None
        PhysxSceneDataBackend->>UsdStage: Traverse()
        loop For each prim
            PhysxSceneDataBackend->>PhysxSceneDataBackend: skip if prim.IsA(UsdPhysics.Joint)
            PhysxSceneDataBackend->>PhysxSceneDataBackend: append if HasAPI(RigidBodyAPI)
        end
        PhysxSceneDataBackend->>PhysxSceneDataBackend: compact env paths to wildcards
        PhysxSceneDataBackend->>PhysxSceneDataBackend: create_rigid_body_view(body_paths)
    end
    PhysxSceneDataBackend-->>SceneDataProvider: rigid body transforms
    SceneDataProvider-->>NewtonManager: transforms written to _state_0.body_q
Loading

Reviews (1): Last reviewed commit: "Fix PhysX scene data for joint-labeled b..." | Re-trigger Greptile

cls._scene_data = SceneDataFormat.Transform()
if cls._scene_data_mapping is None:
body_paths = list(getattr(cls._model, "body_label", None) or [])
body_paths = cls._resolve_scene_data_body_paths(list(cls._model.body_label), scene_data_provider.usd_stage)

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.

P1 The original call used getattr(cls._model, "body_label", None) or [] which safely handled both a missing attribute and a None value. The new code calls list(cls._model.body_label) directly — if body_label is None (which the original guard explicitly anticipated), this raises TypeError: 'NoneType' is not iterable. If the attribute is absent on some model variant, it raises AttributeError. Both crash update_visualization_state at runtime after the surrounding guard already verified only that cls._model is not None.

Suggested change
body_paths = cls._resolve_scene_data_body_paths(list(cls._model.body_label), scene_data_provider.usd_stage)
raw_labels = getattr(cls._model, "body_label", None) or []
body_paths = cls._resolve_scene_data_body_paths(list(raw_labels), scene_data_provider.usd_stage)

Comment on lines +166 to +184
def test_resolve_scene_data_body_paths_uses_joint_body_targets():
"""PhysX visualization sync maps Newton joint labels to the actual body prim path."""
import pytest

pytest.importorskip("pxr")
from isaaclab_newton.physics import NewtonManager

from pxr import Usd, UsdGeom, UsdPhysics

stage = Usd.Stage.CreateInMemory()
body_prim = UsdGeom.Xform.Define(stage, "/World/envs/env_0/Robot/robot0_forearm").GetPrim()
UsdPhysics.RigidBodyAPI.Apply(body_prim)
joint = UsdPhysics.FixedJoint.Define(stage, "/World/envs/env_0/Robot/joints/robot0_forearm")
joint.GetBody1Rel().SetTargets([body_prim.GetPath()])

body_paths = ["/World/envs/env_0/Robot/joints/robot0_forearm"]
resolved_paths = NewtonManager._resolve_scene_data_body_paths(body_paths, stage)

assert resolved_paths == ["/World/envs/env_0/Robot/robot0_forearm"]

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.

P2 pytest.importorskip placed inside the test body rather than at module level is inconsistent with how test_physx_scene_data_backend.py handles the same dependency. Function-level placement works — pytest will skip the test correctly — but moving it to module level would align with the project pattern established in the companion test file.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@ooctipus ooctipus merged commit e2bd110 into isaac-sim:release/3.0.0-beta2 Jun 11, 2026
37 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

isaac-lab Related to Isaac Lab team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants