Skip to content

Adds friction/restitution index APIs and unify material randomization across PhysX and Newton#5098

Open
ooctipus wants to merge 3 commits intoisaac-sim:developfrom
ooctipus:feature/event_mdp_parity
Open

Adds friction/restitution index APIs and unify material randomization across PhysX and Newton#5098
ooctipus wants to merge 3 commits intoisaac-sim:developfrom
ooctipus:feature/event_mdp_parity

Conversation

@ooctipus
Copy link
Copy Markdown
Collaborator

@ooctipus ooctipus commented Mar 24, 2026

Description

This PR extends the material property API across all asset types (Articulation, RigidObject, RigidObjectCollection) and unifies the randomize_rigid_body_material event term to work transparently with both the PhysX and Newton physics backends.

New APIs

  • isaaclab_physx: Adds set_material_properties_index and set_material_properties_mask to all three asset classes, providing a vectorized, index-based alternative to the existing set_material_properties.
  • isaaclab_newton: Adds set_friction_index, set_friction_mask, set_restitution_index, set_restitution_mask, and a num_shapes property to all three asset classes. Newton's friction model uses a single coefficient (mu), so friction and restitution are exposed as separate APIs rather than a combined 3-tuple.

Unified MDP event term
randomize_rigid_body_material now auto-detects the active physics backend at initialization and dispatches to a backend-specific implementation:

  • PhysX path: caches default materials, applies updates via the new set_material_properties_index.
  • Newton path: caches default friction/restitution buffers separately, applies updates via set_friction_index / set_restitution_index.

Type of change

  • New feature (non-breaking change which adds functionality)

Screenshots

Please attach before and after screenshots of the change if applicable.

Checklist

  • I have read and understood the contribution guidelines
  • I have run the pre-commit checks with ./isaaclab.sh --format
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • I have updated the changelog and the corresponding version in the extension's config/extension.toml file
  • I have added my name to the CONTRIBUTORS.md or my name already exists there

@github-actions github-actions bot added enhancement New feature or request isaac-lab Related to Isaac Lab team labels Mar 24, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 24, 2026

Greptile Summary

This PR extends the material property API across all three asset types (Articulation, RigidObject, RigidObjectCollection) for both the PhysX and Newton backends, and unifies the randomize_rigid_body_material and randomize_joint_parameters MDP event terms to auto-detect and dispatch between backends at runtime.

Key changes:

  • PhysX assets: adds set_material_properties_index / set_material_properties_mask that delegate to the existing root_view.set_material_properties TensorAPI, providing a consistent named-parameter interface.
  • Newton assets: adds set_friction_index/mask and set_restitution_index/mask backed by Warp kernels, plus a num_shapes property and the corresponding _ALL_SHAPE_* pre-computed arrays for all three asset classes.
  • Newton data classes: binds shape_material_mu and shape_material_restitution warp attributes and exposes _num_shapes.
  • randomize_rigid_body_material: split into _init_physx / _init_newton / _call_physx / _call_newton helper methods; backend detected once at construction via env.sim.physics_manager.__name__.
  • randomize_joint_parameters: version-check (get_isaac_sim_version().major >= 5) replaced with a backend check; dynamic/viscous friction caching and application are now PhysX-only paths.

Issues found:

  • P0 — Runtime crash for PhysX body-filtered randomization: _init_physx now calls asset.root_view.create_rigid_body_view(link_path), but create_rigid_body_view is only available on _physics_sim_view, not on ArticulationView. Every other call site in the codebase uses _physics_sim_view. The original code also used _physics_sim_view and this change introduces an AttributeError whenever body_ids is not slice(None) with the PhysX backend.
  • P1 — Misleading docstring on set_material_properties_index: All three PhysX asset implementations document materials as (len(env_ids), max_shapes, 3), but _call_physx passes the full (num_envs, max_shapes, 3) buffer — consistent with how the original code used Isaac Sim's TensorAPI (row i of the full buffer is written to physics env env_ids[i]). The docstring needs to reflect actual semantics.
  • P2 — Removed shape-count validation: The defensive sum(num_shapes_per_body) == max_shapes check was dropped from _init_physx without replacement.
  • P2 — Newton path writes full buffer for partial env_ids: _call_newton updates only env_ids rows then calls set_friction_mask / set_restitution_mask on the entire buffer. Using the index variants would be more efficient for partial resets.

Confidence Score: 2/5

  • Not safe to merge — the P0 root_view.create_rigid_body_view bug will crash any PhysX user who filters randomization by body_ids.
  • The Newton additions, the new PhysX set_material_properties_* APIs, and the test coverage are all solid. However, the _init_physx path introduces a clear AttributeError by calling create_rigid_body_view on ArticulationView instead of _physics_sim_view. This is a one-line fix, but it will silently break a common use-case (body-filtered material randomization) that worked correctly before this refactor. The misleading docstring on set_material_properties_index is also worth correcting to avoid caller confusion. Score is 2 rather than lower because the fix is trivial and the rest of the implementation is well-structured.
  • source/isaaclab/isaaclab/envs/mdp/events.py line 258 needs the root_view_physics_sim_view fix before merge.

Important Files Changed

Filename Overview
source/isaaclab/isaaclab/envs/mdp/events.py Core change: refactored randomize_rigid_body_material and randomize_joint_parameters to auto-detect and dispatch between PhysX and Newton backends. Contains a critical bug where _init_physx calls asset.root_view.create_rigid_body_view() — a method that does not exist on ArticulationView and was always routed through _physics_sim_view in the rest of the codebase. Also contains a misleading docstring for set_material_properties_index regarding the expected materials tensor shape.
source/isaaclab_physx/isaaclab_physx/assets/articulation/articulation.py Adds set_material_properties_index and set_material_properties_mask to PhysX Articulation. Implementation correctly delegates to root_view.set_material_properties. Docstring claims materials shape is (len(env_ids), max_shapes, 3) but the calling code passes the full (num_envs, max_shapes, 3) buffer — docstring needs correction across all three PhysX assets.
source/isaaclab_physx/isaaclab_physx/assets/rigid_object/rigid_object.py Adds set_material_properties_index and set_material_properties_mask to PhysX RigidObject. Same implementation pattern as articulation; same docstring inconsistency for materials shape.
source/isaaclab_physx/isaaclab_physx/assets/rigid_object_collection/rigid_object_collection.py Adds set_material_properties_index and set_material_properties_mask to PhysX RigidObjectCollection. Same implementation and docstring inconsistency as the other PhysX assets.
source/isaaclab_newton/isaaclab_newton/assets/articulation/articulation.py Adds num_shapes property, set_friction_index/mask, set_restitution_index/mask, _resolve_shape_ids, and the _ALL_SHAPE_INDICES/_ALL_SHAPE_MASK pre-computed arrays. All new methods follow the existing index/mask pattern consistently and wire correctly to _sim_bind_shape_material_mu and _sim_bind_shape_material_restitution.
source/isaaclab_newton/isaaclab_newton/assets/rigid_object/rigid_object.py Same friction/restitution index and mask APIs added for Newton RigidObject. set_friction_mask handles env_mask=None inline rather than via _resolve_mask, but is functionally equivalent to the articulation.
source/isaaclab_newton/isaaclab_newton/assets/rigid_object_collection/rigid_object_collection.py Same friction/restitution APIs added for Newton RigidObjectCollection. Consistent with other Newton asset implementations.
source/isaaclab_newton/isaaclab_newton/assets/articulation/articulation_data.py Binds shape_material_mu and shape_material_restitution warp attributes and computes _num_shapes. The [:, 0] indexing on the raw attribute result is consistent with how other per-instance attributes are bound, assuming the attribute returns shape (num_instances, 1, num_shapes).
source/isaaclab_newton/test/assets/test_articulation.py Adds test_set_material_properties covering both full-shape and subset-shape index writes for Newton Articulation. Tests both set_friction_index and set_restitution_index and verifies via internal binding reads.
source/isaaclab_physx/test/assets/test_articulation.py Adds test_set_material_properties for PhysX Articulation. Correctly uses articulation.root_view.max_shapes to size the materials tensor and verifies via get_material_properties.

Sequence Diagram

sequenceDiagram
    participant Env as ManagerBasedEnv
    participant Term as randomize_rigid_body_material
    participant PhysX as PhysX Asset
    participant Newton as Newton Asset

    Note over Term: __init__: detect backend via<br/>env.sim.physics_manager.__name__

    alt PhysX backend
        Term->>PhysX: root_view.get_material_properties()
        PhysX-->>Term: default_materials (num_envs, max_shapes, 3) on CPU
        Note over Term: _init_physx(): compute shape_indices<br/>(uses _physics_sim_view.create_rigid_body_view<br/>when body_ids filtered)
    else Newton backend
        Term->>Newton: data._sim_bind_shape_material_mu
        Newton-->>Term: default_friction (num_envs, num_shapes)
        Term->>Newton: data._sim_bind_shape_material_restitution
        Newton-->>Term: default_restitution (num_envs, num_shapes)
    end

    Note over Env,Term: __call__: each environment reset step

    Env->>Term: __call__(env_ids, ...)
    Term->>Term: sample bucket_ids → material_samples

    alt PhysX path (_call_physx)
        Term->>Term: default_materials[env_ids, shape_idx] = material_samples
        Term->>PhysX: set_material_properties_index(default_materials, env_ids)
        PhysX->>PhysX: root_view.set_material_properties(warp_array, env_ids)
    else Newton path (_call_newton)
        Term->>Term: default_friction[env_ids, shape_idx] = material_samples[..., 0]
        Term->>Term: default_restitution[env_ids, shape_idx] = material_samples[..., 2]
        Term->>Newton: set_friction_mask(default_friction)
        Term->>Newton: set_restitution_mask(default_restitution)
        Newton->>Newton: wp.launch(write_2d_data_to_buffer_with_mask)<br/>+ SimulationManager.add_model_change(SHAPE_PROPERTIES)
    end
Loading

Reviews (1): Last reviewed commit: "fix linting" | Re-trigger Greptile

# note: workaround since Articulation doesn't expose shapes per body directly
num_shapes_per_body = []
for link_path in asset.root_view.link_paths[0]: # type: ignore[union-attr]
link_physx_view = asset.root_view.create_rigid_body_view(link_path) # type: ignore
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.

P0 root_view does not expose create_rigid_body_view

ArticulationView (the type behind root_view) does not have a create_rigid_body_view method — that method only exists on the global physics-simulation view (_physics_sim_view). Calling it here will raise AttributeError at runtime whenever body_ids is not slice(None) on a PhysX articulation.

Every other call to create_rigid_body_view in the codebase is routed through _physics_sim_view (e.g. contact_sensor.py, frame_transformer.py, imu.py, the PhysX rigid-object/collection initialization code). The original pre-refactor code also used self.asset._physics_sim_view.create_rigid_body_view(link_path) for exactly this reason.

Suggested change
link_physx_view = asset.root_view.create_rigid_body_view(link_path) # type: ignore
link_physx_view = asset._physics_sim_view.create_rigid_body_view(link_path) # type: ignore


# apply to simulation via PhysX's unified material API
asset: PhysXRigidObject | PhysXArticulation | PhysXRigidObjectCollection = self.asset # type: ignore[assignment]
asset.set_material_properties_index(materials=self.default_materials, env_ids=env_ids)
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 Full buffer passed where partial buffer is documented

self.default_materials has shape (num_envs, max_shapes, 3), but the docstring of set_material_properties_index across all three PhysX asset classes states the expected shape is (len(env_ids), max_shapes, 3).

If the underlying root_view.set_material_properties(materials, env_ids) call interprets materials as a partial tensor (rows indexed by env_ids), then only the first len(env_ids) environments would receive correctly updated values, regardless of which envs are in env_ids.

The original implementation retrieved the full buffer via get_material_properties(), updated the rows for env_ids, and passed the full buffer back — suggesting the IsaacSim TensorAPI reads row i from the full tensor when env_ids[i] is in the index set. The docstring in the new set_material_properties_index is therefore misleading and should match actual usage:

# In all three PhysX asset classes:
# Args:
#     materials: Material properties for all shapes. Shape is (num_envs, max_shapes, 3)
#                where the 3 values are [static_friction, dynamic_friction, restitution].

This same discrepancy appears in all three PhysX asset files:

  • source/isaaclab_physx/isaaclab_physx/assets/articulation/articulation.py
  • source/isaaclab_physx/isaaclab_physx/assets/rigid_object/rigid_object.py
  • source/isaaclab_physx/isaaclab_physx/assets/rigid_object_collection/rigid_object_collection.py

Comment on lines +249 to +271
def _init_physx(self, use_body_ids: bool) -> None:
"""Initialize PhysX-specific state: shape indices and cached materials."""
asset: PhysXArticulation | PhysXRigidObject | PhysXRigidObjectCollection = self.asset # type: ignore[assignment]

# compute shape indices
if use_body_ids:
# note: workaround since Articulation doesn't expose shapes per body directly
num_shapes_per_body = []
for link_path in asset.root_view.link_paths[0]: # type: ignore[union-attr]
link_physx_view = asset.root_view.create_rigid_body_view(link_path) # type: ignore
num_shapes_per_body.append(link_physx_view.max_shapes)
shape_indices_list = []
for body_id in self.asset_cfg.body_ids:
start_idx = sum(num_shapes_per_body[:body_id])
end_idx = start_idx + num_shapes_per_body[body_id]
shape_indices_list.extend(range(start_idx, end_idx))
self.shape_indices = torch.tensor(shape_indices_list, dtype=torch.long)
else:
self.shape_indices = torch.arange(asset.root_view.max_shapes, dtype=torch.long)

# cache default materials
self.default_materials = wp.to_torch(asset.root_view.get_material_properties()).clone()

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 Shape-count validation removed without replacement

The original __init__ included a defensive check after computing num_shapes_per_body:

num_shapes = sum(self.num_shapes_per_body)
expected_shapes = self.asset.root_view.max_shapes
if num_shapes != expected_shapes:
    raise ValueError(
        "Randomization term 'randomize_rigid_body_material' failed to parse the number of shapes per body."
        f" Expected total shapes: {expected_shapes}, but got: {num_shapes}."
    )

This guard caught any mis-parsed shape counts early and produced a clear error. The new _init_physx silently drops it. Consider adding an equivalent assertion after the loop so that configuration errors surface at initialization rather than causing silent, hard-to-diagnose incorrect material assignments at runtime.

Comment on lines +347 to +348
asset.set_friction_mask(friction=self.default_friction)
asset.set_restitution_mask(restitution=self.default_restitution)
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 Newton path writes the full env buffer even for partial env_ids

_call_newton updates only the env_ids rows in self.default_friction / self.default_restitution, but then applies the complete buffer to all environments via set_friction_mask / set_restitution_mask. This is functionally correct (unchanged envs are simply re-written with their existing values), but it launches kernels proportional to num_envs × num_shapes instead of len(env_ids) × len(shape_idx).

The index variants set_friction_index / set_restitution_index are already available and would target only the requested envs and shapes:

def _call_newton(self, env_ids, shape_idx, material_samples):
    self.default_friction[env_ids[:, None], shape_idx] = material_samples[..., 0]
    self.default_restitution[env_ids[:, None], shape_idx] = material_samples[..., 2]

    asset: NewtonRigidObject | NewtonArticulation | NewtonRigidObjectCollection = self.asset
    asset.set_friction_index(
        friction=self.default_friction[env_ids][:, shape_idx],
        shape_ids=shape_idx,
        env_ids=env_ids,
    )
    asset.set_restitution_index(
        restitution=self.default_restitution[env_ids][:, shape_idx],
        shape_ids=shape_idx,
        env_ids=env_ids,
    )

If full-buffer writes are intentional (e.g. for graphed-pipeline compatibility), please add a comment explaining the trade-off.

Copy link
Copy Markdown
Contributor

@kellyguo11 kellyguo11 left a comment

Choose a reason for hiding this comment

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

PR Review: #5098

Summary

This PR adds friction/restitution material property APIs (set_friction_index/mask, set_restitution_index/mask) to Newton assets and set_material_properties_index/mask to PhysX assets, then unifies randomize_rigid_body_material to auto-detect the backend and dispatch accordingly. It also adds a new randomize_rigid_body_inertia event term. The architecture is sound, but there are CI-breaking issues and a few concerns that need attention.

Architecture Assessment

API Symmetry: Intentionally asymmetric by design — Newton exposes separate set_friction_*/set_restitution_* (single mu), while PhysX uses a combined 3-tuple set_material_properties_*. This is well-motivated by the different physics models and documented clearly.

Breaking Changes: No existing public API signatures are changed. The randomize_rigid_body_material event term maintains the same __call__ signature. The randomize_joint_parameters class now conditionally skips dynamic_friction_coeff/viscous_friction_coeff for Newton — this is correct since Newton doesn't have these properties.

Cross-Module Impact: 16 task configs use randomize_rigid_body_material. The unified event term should be transparent to all of them since the __call__ signature is unchanged.

CI Status

🔴 All test jobs failing. The develop branch CI is green (success), confirming these are regressions introduced by this PR.

Critical failure: KeyError: 'shape_material_mu' in Newton's _create_simulation_bindings — the new get_attribute("shape_material_mu", ...) calls break ALL Newton mock-based tests (isaaclab core [3/3] shows 100+ Newton test errors). The mock ArticulationView doesn't have shape_material_mu or shape_material_restitution registered as attributes. This must be fixed before merge.

Other failures: isaaclab_physx (test_rigid_object_collection), isaaclab_mimic, and other jobs also show failures that may cascade from the same root cause or be pre-existing flakiness.

Key Findings

  1. 🔴 Critical: Newton mock views missing shape_material_mu/shape_material_restitution attributes — The new _create_simulation_bindings code in articulation_data.py, rigid_object_data.py, and rigid_object_collection_data.py unconditionally calls get_attribute("shape_material_mu", ...) during construction. The Newton test mock views (mock_articulation_view.py) don't have these attributes registered, causing KeyError in ALL Newton-based tests.

  2. 🟡 Performance: _call_newton uses mask method instead of index method_call_newton calls set_friction_mask(friction=self.default_friction) which writes ALL environments' material properties to the simulator, even when only a subset of env_ids changed. Should use set_friction_index with the specific env_ids for better performance.

  3. 🟡 Newton CHANGELOG is inaccurate — States "Removed shape_material_mu and shape_material_restitution data properties" and "Removed hardcoded default_body_armature" but the diff shows NO removals — only additions. The changelog should accurately reflect what changed.

  4. 🟡 isaaclab_tasks version bump without changelogextension.toml bumps from 1.5.13 to 1.5.14 but there's no corresponding CHANGELOG.rst entry and no source files changed in isaaclab_tasks. This appears to be a spurious version bump.

  5. 🟡 PhysX changelog date mismatch0.5.13 (2026-03-23) but commits are dated 2026-03-24.

  6. 🔵 Missing PhysX tests for RigidObject and RigidObjectCollection — New test_set_material_properties test only covers Articulation in isaaclab_physx. Should add equivalent tests for RigidObject and RigidObjectCollection.

  7. 🔵 Inconsistent _resolve_shape_ids ordering — In Newton articulation.py, list check comes before None check. In rigid_object.py and rigid_object_collection.py, None check comes first. While functionally equivalent, should be consistent across asset types.

  8. 🔵 Code duplication — The set_friction_index/mask and set_restitution_index/mask implementations are nearly identical across all three Newton asset classes (~170 lines each × 3). Consider extracting a mixin or shared helper to reduce maintenance burden.

Copy link
Copy Markdown

@isaaclab-review-bot isaaclab-review-bot bot left a comment

Choose a reason for hiding this comment

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

🤖 Isaac Lab Review Bot - PR #5098

Summary

This PR adds friction/restitution index APIs to Newton assets and unifies the randomize_rigid_body_material MDP event term to work transparently across PhysX and Newton backends. It also adds a new randomize_rigid_body_inertia event term.

Scope: 22 files changed across isaaclab, isaaclab_newton, and isaaclab_physx extensions.


Design Assessment

API Design: ✅ Good

  • The Newton APIs (set_friction_index/mask, set_restitution_index/mask) correctly separate friction and restitution because Newton uses a single friction coefficient (mu) vs PhysX's static/dynamic friction pair.
  • The PhysX APIs (set_material_properties_index/mask) maintain the existing 3-tuple format [static_friction, dynamic_friction, restitution].
  • Both follow the established _index/_mask pattern used throughout Isaac Lab for vectorized property setters.

Unification Approach: ✅ Well-designed

  • Backend detection via env.sim.physics_manager.__name__.lower() is reasonable.
  • Separating _init_physx/_init_newton and _call_physx/_call_newton keeps the code organized.
  • Device handling correctly uses CPU for PhysX (tensor API requirement) and GPU for Newton.

Architecture Impact

Component Impact
Newton Articulation +184 lines (friction/restitution setters, shape indexing)
Newton RigidObject +189 lines (same pattern)
Newton RigidObjectCollection +188 lines (same pattern)
PhysX assets +59 lines each (material properties wrapper)
MDP events.py Major refactor of randomize_rigid_body_material, new randomize_rigid_body_inertia

Data bindings: Newton implementation accesses internal _sim_bind_shape_material_* attributes directly. The TODO comment acknowledges this is not ideal and suggests future API improvements.


Implementation Verdict: ⚠️ Bug Found

Critical Issue in _init_physx:

# In randomize_rigid_body_material._init_physx():
link_physx_view = asset.root_view.create_rigid_body_view(link_path)  # ❌ WRONG

This should be:

link_physx_view = asset._physics_sim_view.create_rigid_body_view(link_path)  # ✅ CORRECT

The root_view is an ArticulationView which does not have create_rigid_body_view(). That method exists on _physics_sim_view (the PhysicsSimulationView). This will cause an AttributeError at runtime when use_body_ids=True on PhysX backend (i.e., when asset_cfg.body_ids != slice(None)).

Location: source/isaaclab/isaaclab/envs/mdp/events.py, line ~255 (in _init_physx method)


Test Coverage

Extension New Tests
isaaclab_newton test_set_material_properties for Articulation ✅
isaaclab_newton Updated test_rigid_body_set_material_properties (unskipped) ✅
isaaclab_newton Updated test_set_material_properties for RigidObjectCollection (unskipped) ✅
isaaclab_physx test_set_material_properties for Articulation ✅
isaaclab_physx test_set_material_properties_index for RigidObject ✅

Missing: No tests for randomize_rigid_body_inertia event term or the unified randomize_rigid_body_material with Newton backend.


CI Status: ❌ Multiple Failures

Job Status Notes
isaaclab_newton test_contact_sensor.py::test_filter_enables_force_matrix - pre-existing flaky test
isaaclab_physx test_rigid_object_collection.py - 3 failures then timeout
isaaclab (core) test_first_frame_textured_rendering.py - unrelated
Others Likely cascading from above

The test_rigid_object_collection.py failures in PhysX may be related to this PR given the new material properties code, but the test timed out before detailed error messages were captured.


Findings

  1. 🔴 Critical: _init_physx calls asset.root_view.create_rigid_body_view() but should call asset._physics_sim_view.create_rigid_body_view(). This will crash when using body_ids filtering on PhysX.

  2. 🟡 Medium: The randomize_rigid_body_inertia class was added but not mentioned in the PR description. Consider updating the description or splitting into a separate PR for clarity.

  3. 🟡 Medium: No MDP event tests for the new randomize_rigid_body_inertia or the refactored randomize_rigid_body_material with Newton backend.

  4. 🟢 Minor: The randomize_joint_parameters class also received backend detection changes for joint friction. This works but the Newton path only sets static friction (correct behavior documented in code).


Review generated by Isaac Lab Review Bot

Copy link
Copy Markdown

@isaaclab-review-bot isaaclab-review-bot bot left a comment

Choose a reason for hiding this comment

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

🤖 Isaac Lab Review Bot — PR #5098

Adds friction/restitution index APIs and unify material randomization across PhysX and Newton

Summary

Clean architectural PR that extends material property APIs (friction/restitution) to Newton assets via set_friction_index/mask and set_restitution_index/mask, adds equivalent set_material_properties_index/mask wrappers for PhysX, and refactors randomize_rigid_body_material to auto-detect the physics backend. Also includes a bonus randomize_rigid_body_inertia event term. Overall design is solid — the backend-specific dispatch pattern is the right approach. I have a few findings below.


🔴 Bug: _init_physx uses root_view.create_rigid_body_view instead of _physics_sim_view.create_rigid_body_view

File: source/isaaclab/isaaclab/envs/mdp/events.py, in _init_physx()

The original code on develop uses:

link_physx_view = self.asset._physics_sim_view.create_rigid_body_view(link_path)

The PR changes this to:

link_physx_view = asset.root_view.create_rigid_body_view(link_path)

root_view is an ArticulationView (or RigidBodyView / RigidObjectCollectionView), not a PhysicsSimulationView. The create_rigid_body_view() method lives on PhysicsSimulationView, not on ArticulationView. This will raise an AttributeError at runtime when use_body_ids=True on the PhysX backend.

Fix: Revert to asset._physics_sim_view.create_rigid_body_view(link_path).


🟡 Inconsistency: _call_newton uses set_friction_mask/set_restitution_mask but _call_physx uses set_material_properties_index

In _call_newton, the code calls asset.set_friction_mask(friction=self.default_friction) and asset.set_restitution_mask(restitution=self.default_restitution) — these are mask methods that update all environments since no env_mask is passed.

In _call_physx, the code calls asset.set_material_properties_index(materials=self.default_materials, env_ids=env_ids) — this is an index method that only updates the specified environments.

While both work correctly (the cached buffers are only mutated for env_ids), the Newton path writes full-buffer data to all simulation environments via the mask write kernel, even for environments that haven't changed. For large env counts with partial resets, this is unnecessary overhead.

Suggestion: Consider using set_friction_index/set_restitution_index with env_ids in _call_newton for consistency and to avoid writing unchanged environments to the sim.


🟡 randomize_rigid_body_inertia not mentioned in PR title/description

The PR title says "Adds friction/restitution index APIs and unify material randomization" but the PR also adds a completely new randomize_rigid_body_inertia event term (~140 lines). This is a significant feature addition that isn't mentioned in the PR description at all, only in the CHANGELOG. Consider:

  1. Updating the PR description to document this addition
  2. Or splitting it into a separate PR for cleaner review history

🟡 num_shapes property inconsistency across Newton assets

The num_shapes property on RigidObject and RigidObjectCollection returns self.data._num_shapes, where _num_shapes is computed as:

self._num_shapes = (
    self._sim_bind_shape_material_mu.shape[1] if len(self._sim_bind_shape_material_mu.shape) > 1 else 1
)

For a rigid body with a single collision shape, _sim_bind_shape_material_mu may be 1D (shape (num_instances,) rather than (num_instances, 1)), which would hit the fallback else 1. This works but is fragile — if the upstream attribute ever changes its squeeze behavior, this silently breaks. Consider adding an assertion or explicit reshape to (num_instances, num_shapes) during binding creation.


🟡 randomize_joint_properties backend detection duplicates pattern

The randomize_joint_properties.__init__ also adds backend detection via env.sim.physics_manager.__name__.lower(). This is the same pattern used in randomize_rigid_body_material.__init__. Consider extracting a shared utility like detect_physics_backend(env) -> str to avoid duplicating this heuristic.


🟢 CI Status

All core CI checks are failing, but this appears to be a pre-existing infrastructure issue (all 10 test shards fail including environments_training, isaaclab_rl, etc.) — not specific to this PR's changes. Pre-commit and docs checks pass.


🟢 Tests

Good test coverage:

  • Newton: Tests for articulation, rigid object, and rigid object collection material properties
  • PhysX: Tests for articulation and rigid object set_material_properties_index
  • Previously-skipped Newton material tests are now unskipped ✅

Checklist concern

The author marked "I have made corresponding changes to the documentation" as unchecked. Since this adds new public API methods (set_friction_index/mask, set_restitution_index/mask, set_material_properties_index/mask), documentation for these should be added.


Review by 🤖 Isaac Lab Review Bot (SHA: 01d83a3)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request isaac-lab Related to Isaac Lab team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants