-
Notifications
You must be signed in to change notification settings - Fork 3.6k
[3.0.0-beta2] Fix PhysX scene data for joint-labeled bodies #6148
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| Fixed | ||
| ^^^^^ | ||
|
|
||
| * Fixed Newton visualizers on PhysX simulations when a Newton body label points | ||
| at a USD joint prim by resolving the label through the joint's rigid-body target. |
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -1835,12 +1835,38 @@ def update_visualization_state(cls, scene_data_provider: SceneDataProvider | Non | |||||||
| if cls._scene_data is None: | ||||||||
| 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) | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
| cls._scene_data_mapping = scene_data_provider.create_mapping(body_paths) | ||||||||
|
|
||||||||
| cls._scene_data.transforms = cls._state_0.body_q | ||||||||
| scene_data_provider.get_transforms(cls._scene_data, mapping=cls._scene_data_mapping) | ||||||||
|
|
||||||||
| @staticmethod | ||||||||
| def _resolve_scene_data_body_paths(body_paths: list[str | None], stage) -> list[str | None]: | ||||||||
| """Map Newton joint labels to their target rigid-body prim paths.""" | ||||||||
| if stage is None: | ||||||||
| return body_paths | ||||||||
|
|
||||||||
| from pxr import UsdPhysics | ||||||||
|
|
||||||||
| def _joint_body_path(prim): | ||||||||
| joint = UsdPhysics.Joint(prim) | ||||||||
| for rel in (joint.GetBody1Rel(), joint.GetBody0Rel()): | ||||||||
| for target_path in rel.GetTargets(): | ||||||||
| target_prim = stage.GetPrimAtPath(target_path) | ||||||||
| if target_prim.IsValid() and target_prim.HasAPI(UsdPhysics.RigidBodyAPI): | ||||||||
| return target_path.pathString | ||||||||
| return None | ||||||||
|
|
||||||||
| resolved_paths = body_paths.copy() | ||||||||
| for index, body_path in enumerate(body_paths): | ||||||||
| if body_path is None: | ||||||||
| continue | ||||||||
| prim = stage.GetPrimAtPath(body_path) | ||||||||
| if prim.IsValid() and prim.IsA(UsdPhysics.Joint): | ||||||||
| resolved_paths[index] = _joint_body_path(prim) or body_path | ||||||||
| return resolved_paths | ||||||||
|
|
||||||||
| @classmethod | ||||||||
| def get_state_1(cls) -> State: | ||||||||
| """Get the next state.""" | ||||||||
|
|
||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| Fixed | ||
| ^^^^^ | ||
|
|
||
| * Fixed PhysX scene-data rigid-body view discovery to ignore USD joint prims | ||
| even when an asset authors ``RigidBodyAPI`` on them. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| # Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md). | ||
| # All rights reserved. | ||
| # | ||
| # SPDX-License-Identifier: BSD-3-Clause | ||
|
|
||
| from types import SimpleNamespace | ||
|
|
||
| import pytest | ||
|
|
||
| pytest.importorskip("pxr") | ||
| pytest.importorskip("omni.physics.tensors") | ||
|
|
||
|
|
||
| def test_scene_data_rigid_body_view_skips_joint_prims_with_rigid_body_api(monkeypatch): | ||
| """Joint prims must not be passed to PhysX tensor rigid-body views.""" | ||
| from isaaclab_physx.physics import physx_manager | ||
| from isaaclab_physx.physics.physx_manager import PhysxSceneDataBackend | ||
|
|
||
| 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_prim = UsdPhysics.FixedJoint.Define(stage, "/World/envs/env_0/Robot/joints/robot0_forearm").GetPrim() | ||
| UsdPhysics.RigidBodyAPI.Apply(joint_prim) | ||
|
|
||
| captured_paths = [] | ||
|
|
||
| class _SimulationView: | ||
| def create_rigid_body_view(self, body_paths): | ||
| captured_paths.extend(body_paths) | ||
| return SimpleNamespace(prim_paths=body_paths) | ||
|
|
||
| monkeypatch.setattr( | ||
| physx_manager.omni.usd, | ||
| "get_context", | ||
| lambda: SimpleNamespace(get_stage=lambda: stage), | ||
| ) | ||
|
|
||
| backend = PhysxSceneDataBackend() | ||
| backend.simulation_view = _SimulationView() | ||
| backend.get_rigid_body_view() | ||
|
|
||
| assert captured_paths == ["/World/envs/env_*/Robot/robot0_forearm"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pytest.importorskipplaced inside the test body rather than at module level is inconsistent with howtest_physx_scene_data_backend.pyhandles 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!