Skip to content

Commit ecd79fa

Browse files
Address PR review: split MDPs, revert asset setters, use view-level APIs
- Revert all friction/restitution/material setter additions from Newton and PhysX asset classes (9 files). Material property operations stay at the view level. - Split randomize_rigid_body_material into backend-specific classes: PhysX uses bucket-based 3-tuple materials via root_view; Newton samples friction/restitution continuously per shape via view-level attribute bindings. - Convert randomize_rigid_body_com from function to ManagerTermBase class with cached defaults for repeatable randomization. - Split randomize_rigid_body_collider_offsets into backend-specific classes: PhysX uses rest/contact offsets; Newton maps to shape_margin/shape_gap. - Add BaseRigidObjectCollection support to randomize_rigid_body_inertia. - Fix _physics_sim_view bug (was incorrectly using root_view). - Restore shape-count validation in PhysX material init. - Rewrite all tests to use view-level APIs instead of asset setters. - Un-skip Newton rigid object material tests; skip friction/restitution behavior tests that are incompatible with MuJoCo physics model. - Remove stale Newton/PhysX changelog entries, rewrite isaaclab entry.
1 parent caca5c2 commit ecd79fa

18 files changed

Lines changed: 516 additions & 1170 deletions

File tree

source/isaaclab/docs/CHANGELOG.rst

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,24 @@ Added
88
^^^^^
99

1010
* Added :class:`~isaaclab.envs.mdp.randomize_rigid_body_inertia` event term for
11-
randomizing body inertia tensors. Supports diagonal-only and full 3x3 modes.
11+
randomizing body inertia tensors independently of mass. Supports diagonal-only
12+
(Ixx, Iyy, Izz) and full 3x3 modes.
1213

1314
Changed
1415
^^^^^^^
1516

16-
* Updated :class:`~isaaclab.envs.mdp.randomize_rigid_body_material` to use
17-
backend-specific APIs (PhysX 3-tuple vs Newton separate friction/restitution).
17+
* Split :class:`~isaaclab.envs.mdp.randomize_rigid_body_material` into
18+
backend-specific implementations. PhysX uses bucket-based 3-tuple materials via the
19+
tensor API; Newton samples friction and restitution continuously per shape via
20+
view-level attribute bindings.
21+
* Converted :func:`~isaaclab.envs.mdp.randomize_rigid_body_com` from a plain function
22+
to a :class:`~isaaclab.managers.ManagerTermBase` class with repeatable randomization
23+
from cached defaults. Newton passes position-only (vec3); PhysX passes full pose
24+
(pos + quat).
1825
* Converted :func:`~isaaclab.envs.mdp.randomize_rigid_body_collider_offsets` from a
19-
plain function to a :class:`~isaaclab.managers.ManagerTermBase` class with automatic
20-
backend detection. PhysX uses rest/contact offsets directly; Newton maps them to
21-
``shape_margin`` and ``shape_gap``.
22-
* Updated :func:`~isaaclab.envs.mdp.randomize_rigid_body_com` to detect the active
23-
physics backend and pass position-only (vec3) for Newton vs full pose (pos + quat)
24-
for PhysX.
26+
plain function to a :class:`~isaaclab.managers.ManagerTermBase` class with
27+
backend-specific implementations. PhysX uses rest/contact offsets directly; Newton
28+
maps them to ``shape_margin`` and ``shape_gap``.
2529

2630

2731
4.5.30 (2026-04-13)

source/isaaclab/isaaclab/envs/mdp/events.py

Lines changed: 395 additions & 292 deletions
Large diffs are not rendered by default.

source/isaaclab_newton/docs/CHANGELOG.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Added
2222
registration, wildcard body matching, and zero-copy transform views.
2323

2424

25+
2526
0.5.10 (2026-04-05)
2627
~~~~~~~~~~~~~~~~~~~
2728

source/isaaclab_newton/isaaclab_newton/assets/articulation/articulation.py

Lines changed: 0 additions & 184 deletions
Original file line numberDiff line numberDiff line change
@@ -169,11 +169,6 @@ def num_shapes_per_body(self) -> list[int]:
169169
self._num_shapes_per_body.append(len(shapes))
170170
return self._num_shapes_per_body
171171

172-
@property
173-
def num_shapes(self) -> int:
174-
"""Total number of collision shapes in the articulation."""
175-
return self.data._num_shapes
176-
177172
@property
178173
def joint_names(self) -> list[str]:
179174
"""Ordered names of joints in articulation."""
@@ -2273,168 +2268,6 @@ def set_inertias_mask(
22732268
# tell the physics engine that some of the body properties have been updated
22742269
SimulationManager.add_model_change(SolverNotifyFlags.BODY_INERTIAL_PROPERTIES)
22752270

2276-
def set_friction_index(
2277-
self,
2278-
*,
2279-
friction: torch.Tensor | wp.array,
2280-
shape_ids: Sequence[int] | torch.Tensor | wp.array | None = None,
2281-
env_ids: Sequence[int] | torch.Tensor | wp.array | None = None,
2282-
) -> None:
2283-
"""Set friction coefficient (mu) for collision shapes using indices.
2284-
2285-
.. note::
2286-
This method expects partial data.
2287-
2288-
.. tip::
2289-
Both the index and mask methods have dedicated optimized implementations. Performance is similar for both.
2290-
However, to allow graphed pipelines, the mask method must be used.
2291-
2292-
Args:
2293-
friction: Friction coefficient for shapes. Shape is (len(env_ids), len(shape_ids)).
2294-
shape_ids: Shape indices. If None, all shapes are updated.
2295-
env_ids: Environment indices. If None, all environments are updated.
2296-
"""
2297-
# resolve all indices
2298-
env_ids = self._resolve_env_ids(env_ids)
2299-
shape_ids = self._resolve_shape_ids(shape_ids)
2300-
self.assert_shape_and_dtype(friction, (env_ids.shape[0], shape_ids.shape[0]), wp.float32, "friction")
2301-
# Warp kernels can ingest torch tensors directly, so we don't need to convert to warp arrays here.
2302-
wp.launch(
2303-
shared_kernels.write_2d_data_to_buffer_with_indices,
2304-
dim=(env_ids.shape[0], shape_ids.shape[0]),
2305-
inputs=[
2306-
friction,
2307-
env_ids,
2308-
shape_ids,
2309-
],
2310-
outputs=[
2311-
self.data._sim_bind_shape_material_mu,
2312-
],
2313-
device=self.device,
2314-
)
2315-
# tell the physics engine that some of the shape properties have been updated
2316-
SimulationManager.add_model_change(SolverNotifyFlags.SHAPE_PROPERTIES)
2317-
2318-
def set_friction_mask(
2319-
self,
2320-
*,
2321-
friction: torch.Tensor | wp.array,
2322-
env_mask: wp.array | None = None,
2323-
) -> None:
2324-
"""Set friction coefficient (mu) for collision shapes using masks.
2325-
2326-
.. note::
2327-
This method expects full data.
2328-
2329-
.. tip::
2330-
Both the index and mask methods have dedicated optimized implementations. Performance is similar for both.
2331-
However, to allow graphed pipelines, the mask method must be used.
2332-
2333-
Args:
2334-
friction: Friction coefficient for all shapes. Shape is (num_instances, num_shapes).
2335-
env_mask: Environment mask. If None, then all the instances are updated. Shape is (num_instances,).
2336-
"""
2337-
# resolve masks
2338-
env_mask = self._resolve_mask(env_mask, self._ALL_ENV_MASK)
2339-
shape_mask = self._ALL_SHAPE_MASK
2340-
self.assert_shape_and_dtype_mask(friction, (env_mask, shape_mask), wp.float32, "friction")
2341-
wp.launch(
2342-
shared_kernels.write_2d_data_to_buffer_with_mask,
2343-
dim=(env_mask.shape[0], shape_mask.shape[0]),
2344-
inputs=[
2345-
friction,
2346-
env_mask,
2347-
shape_mask,
2348-
],
2349-
outputs=[
2350-
self.data._sim_bind_shape_material_mu,
2351-
],
2352-
device=self.device,
2353-
)
2354-
# tell the physics engine that some of the shape properties have been updated
2355-
SimulationManager.add_model_change(SolverNotifyFlags.SHAPE_PROPERTIES)
2356-
2357-
def set_restitution_index(
2358-
self,
2359-
*,
2360-
restitution: torch.Tensor | wp.array,
2361-
shape_ids: Sequence[int] | torch.Tensor | wp.array | None = None,
2362-
env_ids: Sequence[int] | torch.Tensor | wp.array | None = None,
2363-
) -> None:
2364-
"""Set restitution coefficient for collision shapes using indices.
2365-
2366-
.. note::
2367-
This method expects partial data.
2368-
2369-
.. tip::
2370-
Both the index and mask methods have dedicated optimized implementations. Performance is similar for both.
2371-
However, to allow graphed pipelines, the mask method must be used.
2372-
2373-
Args:
2374-
restitution: Restitution coefficient for shapes. Shape is (len(env_ids), len(shape_ids)).
2375-
shape_ids: Shape indices. If None, all shapes are updated.
2376-
env_ids: Environment indices. If None, all environments are updated.
2377-
"""
2378-
# resolve all indices
2379-
env_ids = self._resolve_env_ids(env_ids)
2380-
shape_ids = self._resolve_shape_ids(shape_ids)
2381-
self.assert_shape_and_dtype(restitution, (env_ids.shape[0], shape_ids.shape[0]), wp.float32, "restitution")
2382-
# Warp kernels can ingest torch tensors directly, so we don't need to convert to warp arrays here.
2383-
wp.launch(
2384-
shared_kernels.write_2d_data_to_buffer_with_indices,
2385-
dim=(env_ids.shape[0], shape_ids.shape[0]),
2386-
inputs=[
2387-
restitution,
2388-
env_ids,
2389-
shape_ids,
2390-
],
2391-
outputs=[
2392-
self.data._sim_bind_shape_material_restitution,
2393-
],
2394-
device=self.device,
2395-
)
2396-
# tell the physics engine that some of the shape properties have been updated
2397-
SimulationManager.add_model_change(SolverNotifyFlags.SHAPE_PROPERTIES)
2398-
2399-
def set_restitution_mask(
2400-
self,
2401-
*,
2402-
restitution: torch.Tensor | wp.array,
2403-
env_mask: wp.array | None = None,
2404-
) -> None:
2405-
"""Set restitution coefficient for collision shapes using masks.
2406-
2407-
.. note::
2408-
This method expects full data.
2409-
2410-
.. tip::
2411-
Both the index and mask methods have dedicated optimized implementations. Performance is similar for both.
2412-
However, to allow graphed pipelines, the mask method must be used.
2413-
2414-
Args:
2415-
restitution: Restitution coefficient for all shapes. Shape is (num_instances, num_shapes).
2416-
env_mask: Environment mask. If None, then all the instances are updated. Shape is (num_instances,).
2417-
"""
2418-
# resolve masks
2419-
env_mask = self._resolve_mask(env_mask, self._ALL_ENV_MASK)
2420-
shape_mask = self._ALL_SHAPE_MASK
2421-
self.assert_shape_and_dtype_mask(restitution, (env_mask, shape_mask), wp.float32, "restitution")
2422-
wp.launch(
2423-
shared_kernels.write_2d_data_to_buffer_with_mask,
2424-
dim=(env_mask.shape[0], shape_mask.shape[0]),
2425-
inputs=[
2426-
restitution,
2427-
env_mask,
2428-
shape_mask,
2429-
],
2430-
outputs=[
2431-
self.data._sim_bind_shape_material_restitution,
2432-
],
2433-
device=self.device,
2434-
)
2435-
# tell the physics engine that some of the shape properties have been updated
2436-
SimulationManager.add_model_change(SolverNotifyFlags.SHAPE_PROPERTIES)
2437-
24382271
def set_joint_position_target_index(
24392272
self,
24402273
*,
@@ -3401,8 +3234,6 @@ def _create_buffers(self):
34013234
self._ALL_JOINT_MASK = wp.ones((self.num_joints,), dtype=wp.bool, device=self.device)
34023235
self._ALL_BODY_INDICES = wp.array(np.arange(self.num_bodies, dtype=np.int32), device=self.device)
34033236
self._ALL_BODY_MASK = wp.ones((self.num_bodies,), dtype=wp.bool, device=self.device)
3404-
self._ALL_SHAPE_INDICES = wp.array(np.arange(self.num_shapes, dtype=np.int32), device=self.device)
3405-
self._ALL_SHAPE_MASK = wp.ones((self.num_shapes,), dtype=wp.bool, device=self.device)
34063237
self._ALL_FIXED_TENDON_INDICES = wp.array(np.arange(self.num_fixed_tendons, dtype=np.int32), device=self.device)
34073238
self._ALL_FIXED_TENDON_MASK = wp.ones((self.num_fixed_tendons,), dtype=wp.bool, device=self.device)
34083239
self._ALL_SPATIAL_TENDON_INDICES = wp.array(
@@ -3900,21 +3731,6 @@ def _resolve_body_ids(self, body_ids: Sequence[int] | torch.Tensor | wp.array |
39003731
return self._ALL_BODY_INDICES
39013732
return body_ids
39023733

3903-
def _resolve_shape_ids(self, shape_ids: Sequence[int] | torch.Tensor | wp.array | None) -> wp.array | torch.Tensor:
3904-
"""Resolve shape indices to a warp array or tensor.
3905-
3906-
Args:
3907-
shape_ids: Shape indices. If None, then all indices are used.
3908-
3909-
Returns:
3910-
A warp array of shape indices or a tensor of shape indices.
3911-
"""
3912-
if (shape_ids is None) or (shape_ids == slice(None)):
3913-
return self._ALL_SHAPE_INDICES
3914-
elif isinstance(shape_ids, list):
3915-
return wp.array(shape_ids, dtype=wp.int32, device=self.device)
3916-
return shape_ids
3917-
39183734
def _resolve_fixed_tendon_ids(
39193735
self, tendon_ids: Sequence[int] | torch.Tensor | wp.array | None
39203736
) -> wp.array | torch.Tensor:

source/isaaclab_newton/isaaclab_newton/assets/articulation/articulation_data.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1323,16 +1323,6 @@ def _create_simulation_bindings(self) -> None:
13231323
self._sim_bind_joint_velocity_target = wp.zeros(
13241324
(self._num_instances, 0), dtype=wp.float32, device=self.device
13251325
)
1326-
# -- shape material properties (for collision shapes)
1327-
self._sim_bind_shape_material_mu = self._root_view.get_attribute(
1328-
"shape_material_mu", SimulationManager.get_model()
1329-
)[:, 0]
1330-
self._sim_bind_shape_material_restitution = self._root_view.get_attribute(
1331-
"shape_material_restitution", SimulationManager.get_model()
1332-
)[:, 0]
1333-
self._num_shapes = (
1334-
self._sim_bind_shape_material_mu.shape[1] if len(self._sim_bind_shape_material_mu.shape) > 1 else 1
1335-
)
13361326

13371327
def _create_buffers(self) -> None:
13381328
"""Create buffers for the root data."""

0 commit comments

Comments
 (0)