Skip to content

Decouple physics-engine event terms into per-backend modules#5915

Open
ooctipus wants to merge 1 commit into
isaac-sim:developfrom
ooctipus:zhengyuz/decouple-physics-events
Open

Decouple physics-engine event terms into per-backend modules#5915
ooctipus wants to merge 1 commit into
isaac-sim:developfrom
ooctipus:zhengyuz/decouple-physics-events

Conversation

@ooctipus
Copy link
Copy Markdown
Collaborator

@ooctipus ooctipus commented Jun 2, 2026

Summary

  • Splits the physics-property randomization event terms out of isaaclab.envs.mdp.events into a new isaaclab.envs.mdp.physics_events module: randomize_rigid_body_material, randomize_rigid_body_scale, randomize_rigid_body_mass, randomize_rigid_body_inertia, randomize_rigid_body_com, randomize_rigid_body_collider_offsets, randomize_physics_scene_gravity, randomize_joint_parameters, randomize_fixed_tendon_parameters, randomize_actuator_gains (plus the shared randomize_prop_by_op / validate_scale_range helpers). events.py now only holds backend-agnostic terms (resets, force/velocity, visual material/color).
  • Relocates the backend-specific implementations into isaaclab_<backend>.envs.mdp.physics_events for PhysX, Newton, and OVPhysX. The core public terms resolve the active backend's implementation at runtime via a small private resolver, so isaaclab.envs.mdp.events/physics_events no longer import pxr or any backend.
  • OVPhysX reuses the PhysX implementations for every term except material randomization, which has a dedicated no-op (the OVPhysX material tensor binding is not yet available).
  • Deprecates randomize_rigid_body_scale: it remains PhysX-only (Newton raises NotImplementedError) and emits a DeprecationWarning recommending multi-asset spawning (MultiAssetSpawnerCfg).
  • New extension envs/mdp packages follow the lazy __init__.py + .pyi stub convention.

Test plan

  • ./isaaclab.sh -p -m pytest source/isaaclab_physx/test/assets/test_newton_actuators_physx.py
  • ./isaaclab.sh -p -m pytest source/isaaclab_newton/test/assets/test_newton_actuators_newton.py
  • Run an env that uses randomize_rigid_body_material / randomize_joint_parameters on both the PhysX and Newton backends and confirm parity with the previous behavior.
  • Confirm randomize_rigid_body_scale raises on Newton and warns (deprecated) on PhysX.

Note: changelog fragments are not yet included; happy to add per-package fragments if desired.

@github-actions github-actions Bot added the isaac-lab Related to Isaac Lab team label Jun 2, 2026
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.

Follow-up Review for ce76b255 (split events)

This commit completes the refactoring by splitting physics event terms into per-backend modules. The architecture is now clean and extensible.

✅ What Works Well

  1. Clean backend resolution via _resolve_backend_event() - The dynamic import pattern with substring matching for manager names handles all backend variants gracefully (Newton, OVPhysX, PhysX)

  2. Proper re-export structure - Each backend owns its implementations:

    • isaaclab_physx.envs.mdp.physics_events - Full PhysX implementations
    • isaaclab_newton.envs.mdp.physics_events - Newton-specific implementations
    • isaaclab_ovphysx.envs.mdp.physics_events - Reuses PhysX + no-op material randomization
  3. Helper functions properly exposed - randomize_prop_by_op() and validate_scale_range() are now public in physics_events.py for backend implementations to import

  4. Changelog entries are complete - All packages (isaaclab, isaaclab_experimental, isaaclab_newton, isaaclab_ovphysx, isaaclab_physx) have proper changelog fragments

  5. Type hints preserved - The __init__.pyi correctly imports from both events and physics_events modules

🔍 Items Requiring Attention

  1. OVPhysX module missing __all__ export consistency

    • isaaclab_ovphysx.envs.mdp.physics_events defines __all__ but imports from isaaclab_physx
    • The re-exported classes like RandomizeActuatorGains are imported but the module structure should verify they are actually accessible via from isaaclab_ovphysx.envs.mdp import RandomizeActuatorGains
  2. randomize_rigid_body_scale duplication

    • The function exists in both physics_events.py (core module with deprecation warning) AND isaaclab_physx.envs.mdp.physics_events.RandomizeRigidBodyScale
    • The Newton backend raises NotImplementedError for this term
    • Consider removing the PhysX class implementation since the core function already handles USD authoring (backend-agnostic)
  3. Module import path in _resolve_backend_event()

    module = importlib.import_module(f"isaaclab_{backend}.envs.mdp")
    impl_cls = getattr(module, impl_name)
    • This assumes the class is exposed at the envs.mdp level, but the implementations are in envs.mdp.physics_events
    • Verify that isaaclab_<backend>/envs/mdp/__init__.py re-exports these classes
  4. Test import path updates

    • The test files correctly updated the import from isaaclab.envs.mdp.events to isaaclab.envs.mdp.physics_events
    • ✅ This is correct since the public API is now via physics_events

📝 Minor Suggestions

  1. Docstring for _resolve_backend_event() - Consider adding a note about the import resolution order (ovphysx before physx due to substring matching)

  2. Changelog version consistency - isaaclab_experimental bumped to 0.1.0 which is a minor version bump. Verify this aligns with the semantic versioning policy for the other packages


Overall: The refactoring is well-structured and follows the backend abstraction pattern used elsewhere in IsaacLab. The main concern is verifying the import paths actually work at runtime - the _resolve_backend_event() function imports from isaaclab_{backend}.envs.mdp but the implementations are in the physics_events submodule. Please confirm the __init__.py files in each backend package re-export these classes.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Jun 2, 2026

Greptile Summary

This PR decouples physics-engine-specific event terms from the generic isaaclab.envs.mdp.events module by introducing a new physics_events.py in the core package plus per-backend implementations under isaaclab_physx, isaaclab_newton, and isaaclab_ovphysx. A small runtime resolver (_resolve_backend_event) dispatches to the correct backend at construction time, eliminating pxr/warp imports from the public surface.

  • Backend-agnostic terms (resets, external forces, visual material) remain in events.py; all physics-property randomization terms move to physics_events.py with delegation to per-backend classes.
  • randomize_rigid_body_scale is deprecated and raises NotImplementedError on Newton; OVPhysX reuses PhysX implementations except for material randomization (documented no-op).
  • Backend modules adopt a lazy __init__.py + .pyi stub convention consistent with the rest of the codebase.

Confidence Score: 3/5

Two real behavioral defects need fixing: gravity randomization on PhysX silently falls back to uniform regardless of configuration, and the Newton collider-offset implementation permanently overwrites stored defaults on each call.

The PhysX gravity implementation hardcodes distribution='uniform' inside randomize_prop_by_op, discarding any configured distribution. Newton's RandomizeRigidBodyColliderOffsets mutates self.default_margin in-place, making repeated resets over disjoint env_ids subsets accumulate drift.

source/isaaclab_physx/isaaclab_physx/envs/mdp/physics_events.py (gravity distribution) and source/isaaclab_newton/isaaclab_newton/envs/mdp/physics_events.py (collider default margin mutation)

Important Files Changed

Filename Overview
source/isaaclab/isaaclab/envs/mdp/physics_events.py New public module with backend-agnostic wrappers delegating via _resolve_backend_event; confusing deprecation+error ordering for randomize_rigid_body_scale on Newton.
source/isaaclab_physx/isaaclab_physx/envs/mdp/physics_events.py PhysX backend implementations; RandomizePhysicsSceneGravity hardcodes distribution="uniform", silently ignoring any user-configured distribution.
source/isaaclab_newton/isaaclab_newton/envs/mdp/physics_events.py Newton backend implementations; RandomizeRigidBodyColliderOffsets mutates self.default_margin on every call, diverging from original defaults across resets.
source/isaaclab_ovphysx/isaaclab_ovphysx/envs/mdp/physics_events.py OVPhysX no-op for material randomization with a clear warning; all other terms fall through to PhysX backend.
source/isaaclab/isaaclab/envs/mdp/events.py Physics-property randomization moved to physics_events.py; now holds only backend-agnostic resets and visual-material terms.
source/isaaclab/isaaclab/envs/mdp/init.pyi Stub updated to re-export physics terms from physics_events and visual/reset terms from events; split looks correct.
source/isaaclab_ovphysx/isaaclab_ovphysx/envs/mdp/init.py Stale _EventTermFactory reference in docstring; the actual router is _resolve_backend_event.

Reviews (1): Last reviewed commit: "Decouple physics-engine event terms into..." | Re-trigger Greptile

Comment on lines +265 to +274
gravity = randomize_prop_by_op(
gravity,
(self._dist_param_0.cpu(), self._dist_param_1.cpu()),
None,
slice(None),
operation=operation,
distribution="uniform",
)
gravity = gravity[0].tolist()
self._physics_sim_view.set_gravity(self._carb.Float3(*gravity))
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 Distribution parameter silently ignored on PhysX

randomize_prop_by_op is called with a hardcoded distribution="uniform", so any value configured in cfg.params["distribution"] (e.g. "log_uniform" or "gaussian") is silently discarded. Newton's RandomizePhysicsSceneGravity.__init__ correctly caches the configured distribution function in self._dist_fn, but the PhysX implementation never stores it. A user who sets distribution="gaussian" on PhysX will silently get uniform sampling with no error or warning.

Comment on lines +158 to +160
)
self.default_margin[env_ids] = margin[env_ids]
margin_view[env_ids] = margin[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 default_margin mutated across calls, diverging from original defaults

self.default_margin[env_ids] = margin[env_ids] permanently overwrites the stored defaults. On the next reset for a different env_ids subset, those environments' default margin is the previously randomized value rather than the original scene default. The PhysX counterpart always clones from self.default_rest_offsets (never mutated). Because the operation is currently hardcoded to "abs" the mutation does not affect output values today, but would silently break if "add" or "scale" support is added.

Comment on lines +11 to +13
OVPhysX reuses the PhysX implementations for most event terms (see the ``ovphysx -> physx``
fallback in :class:`~isaaclab.envs.mdp.physics_events._EventTermFactory`); only terms that need a
different OVPhysX behavior are defined here.
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 The docstring references _EventTermFactory, a class that does not exist in the codebase. The runtime routing is the module-level function _resolve_backend_event in isaaclab.envs.mdp.physics_events.

Suggested change
OVPhysX reuses the PhysX implementations for most event terms (see the ``ovphysx -> physx``
fallback in :class:`~isaaclab.envs.mdp.physics_events._EventTermFactory`); only terms that need a
different OVPhysX behavior are defined here.
OVPhysX reuses the PhysX implementations for most event terms (see the ``ovphysx -> physx``
fallback in :func:`~isaaclab.envs.mdp.physics_events._resolve_backend_event`); only terms that need a
different OVPhysX behavior are defined here.

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!

Comment on lines +116 to +124
warnings.warn(
"'randomize_rigid_body_scale' is deprecated and only supported on the PhysX backend. Prefer"
" multi-asset spawning (see :class:`~isaaclab.sim.MultiAssetSpawnerCfg`) with per-scale USD"
" variants instead.",
DeprecationWarning,
stacklevel=2,
)
# the USD scale authoring is backend-specific; resolve the active backend's implementation
_resolve_backend_event("RandomizeRigidBodyScale")(env, env_ids, scale_range, asset_cfg, relative_child_path)
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 Confusing warning/error ordering for Newton users

On Newton, randomize_rigid_body_scale first emits a DeprecationWarning saying the function is "only supported on the PhysX backend", then immediately raises NotImplementedError. Users on Newton see the deprecation first, implying it could work if they switch backends, before hitting an uncaught error. The Newton path should skip the PhysX-flavored deprecation warning and raise NotImplementedError directly.

@ooctipus ooctipus force-pushed the zhengyuz/decouple-physics-events branch 4 times, most recently from 527813b to 1f45c56 Compare June 2, 2026 10:02
@ooctipus ooctipus force-pushed the zhengyuz/decouple-physics-events branch from 1f45c56 to ce76b25 Compare June 3, 2026 08:48
YizeWang pushed a commit to YizeWang/IsaacLab that referenced this pull request Jun 3, 2026
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.

1 participant