-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Add Newton viewer rigid-body dragging #6696
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
Merged
kellyguo11
merged 33 commits into
isaac-sim:develop
from
maxkra15:max/newton-viewer-support
Aug 8, 2026
Merged
Changes from 20 commits
Commits
Show all changes
33 commits
Select commit
Hold shift + click to select a range
003103a
feat: support Newton viewer controls and MJWarp dragging
maxkra15 a583ddf
Merge upstream/develop into viewer support
maxkra15 0fe8ed3
Update Newton marker viewer test double
maxkra15 e7ca9dd
Merge upstream/develop into viewer support
maxkra15 2b4ed51
Merge remote-tracking branch 'upstream/develop' into max/newton-viewe…
maxkra15 8796cf5
Narrow Newton viewer support to dragging
maxkra15 8084b4e
Support Newton dragging across rigid solvers
maxkra15 fb173a4
Merge remote-tracking branch 'upstream/develop' into max/newton-viewe…
maxkra15 0b2e94c
Simplify Newton viewer dragging bridge
maxkra15 7c475e6
feat: support coupled Newton viewer dragging
maxkra15 76256a3
style: format coupled MPM demo
maxkra15 9eb9d3c
refactor: lighten coupled MPM demo
maxkra15 2f92792
refactor: canonicalize Newton force capability
maxkra15 5e2939a
Merge upstream develop into Newton viewer support
maxkra15 ea519ee
Merge remote-tracking branch 'upstream/develop' into max/newton-viewe…
maxkra15 4dbabac
Merge remote-tracking branch 'upstream/develop' into max/newton-viewe…
maxkra15 fb7e7a0
refactor: remove coupled MPM viewer demo
maxkra15 6f9198e
Merge branch 'develop' into max/newton-viewer-support
kellyguo11 5e59367
Add focused Newton dragging demos
maxkra15 863e07a
Merge remote-tracking branch 'origin/max/newton-viewer-support' into …
maxkra15 c354ac9
Merge remote-tracking branch 'upstream/develop' into max/newton-viewe…
maxkra15 10b8772
Align viewer branch with landed MPM fix
maxkra15 ee89994
Clarify viewer capture and demo settings
maxkra15 194fb37
Merge remote-tracking branch 'upstream/develop' into max/newton-viewe…
maxkra15 36f1d37
Move MPM demo import to module scope
maxkra15 98b2abf
Contain coupled MPM demo in particle bath
maxkra15 064d1a4
Increase coupled MPM bath density
maxkra15 d693680
Tune coupled MPM bath interaction
maxkra15 9765759
Soften coupled MPM bath material
maxkra15 c56dd2f
Color spheres and lower MPM bath walls
maxkra15 11fe762
Use canonical Newton GL demo defaults
maxkra15 16b6583
Add three-way chutes to coupled MPM demo
maxkra15 2bea3e5
Address Newton viewer review feedback
maxkra15 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,216 @@ | ||
| # 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 | ||
|
|
||
| """Drag three rigid boxes coupled to Newton implicit-MPM sand. | ||
|
|
||
| This Isaac Lab port of Newton's ``mpm_twoway_coupling`` example uses a proxy | ||
| coupler to expose dynamic rigid boxes as MPM colliders and feed the resulting | ||
| impulses back into the rigid-body solver. | ||
|
|
||
| .. code-block:: bash | ||
|
|
||
| uv run python scripts/demos/mpm/newton_mpm_twoway_coupling.py | ||
|
|
||
| Right-click and drag a box to apply an interactive force. Use ``Space`` to | ||
| pause or resume the simulation and ``.`` to advance one step while paused. | ||
| """ | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import argparse | ||
|
|
||
| from isaaclab.app import add_launcher_args, launch_simulation | ||
|
|
||
| parser = argparse.ArgumentParser(description="Newton rigid-box and MPM-sand two-way coupling demo.") | ||
| parser.add_argument("--max_steps", type=int, default=-1, help="Stop after this many frames; negative runs forever.") | ||
| parser.add_argument("--voxel_size", type=float, default=0.075, help="MPM grid voxel size [m].") | ||
| parser.add_argument("--rigid_substeps", type=int, default=4, help="Rigid-solver substeps per coupled step.") | ||
| add_launcher_args(parser) | ||
| parser.set_defaults(visualizer=["newton"]) | ||
| args_cli = parser.parse_args() | ||
|
|
||
|
|
||
| FPS = 100.0 | ||
| GRAVITY = (0.0, 0.0, -9.81) | ||
| PARTICLES_PER_CELL = 3.0 | ||
| PARTICLE_COLOR = (0.7, 0.6, 0.4) | ||
|
|
||
| BOX_BODY_PATTERN = r"/World/envs/env_.*/Box_[0-9]+" | ||
| BOX_HALF_EXTENTS = ( | ||
| (0.25, 0.35, 0.25), | ||
| (0.25, 0.25, 0.25), | ||
| (0.30, 0.20, 0.20), | ||
| ) | ||
| # Match Newton's reference scene: 75 kg body mass plus the shape's | ||
| # default-density contribution. | ||
| BOX_MASSES = (250.0, 200.0, 171.0) | ||
| BOX_OFFSETS_XY = ( | ||
| (0.00, 0.00), | ||
| (0.10, 0.00), | ||
| (-0.10, 0.00), | ||
| ) | ||
|
|
||
|
|
||
| def create_visualizer_cfgs(): | ||
| """Create the demo-specific Newton visualizer configuration.""" | ||
| if "newton" not in (args_cli.visualizer or []): | ||
| return [] | ||
|
|
||
| from isaaclab_visualizers.newton import NewtonVisualizerCfg | ||
|
|
||
| return [ | ||
| NewtonVisualizerCfg( | ||
| show_particles=True, | ||
| particle_color=PARTICLE_COLOR, | ||
| update_frequency=1, | ||
| ) | ||
| ] | ||
|
|
||
|
|
||
| def create_sim_cfg(): | ||
| """Create the proxy-coupled MJWarp and MPM simulation configuration.""" | ||
| from isaaclab_newton.physics import MJWarpSolverCfg, MPMSolverCfg, NewtonCfg | ||
|
|
||
| import isaaclab.sim as sim_utils | ||
|
|
||
| from isaaclab_contrib.coupling import CouplerEntryCfg, CouplerProxyCfg, CouplerProxyMappingCfg | ||
|
|
||
| solver_cfg = CouplerProxyCfg( | ||
| entries=[ | ||
| CouplerEntryCfg( | ||
| name="rigid", | ||
| solver_cfg=MJWarpSolverCfg(use_mujoco_contacts=False, njmax=128), | ||
| bodies=[BOX_BODY_PATTERN], | ||
| include_static_shapes=True, | ||
| substeps=args_cli.rigid_substeps, | ||
| ), | ||
| CouplerEntryCfg( | ||
| name="mpm", | ||
| solver_cfg=MPMSolverCfg( | ||
| voxel_size=args_cli.voxel_size, | ||
| grid_type="fixed", | ||
| grid_padding=50, | ||
| max_active_cell_count=1 << 15, | ||
| strain_basis="P0", | ||
| max_iterations=50, | ||
| critical_fraction=0.0, | ||
| ), | ||
| all_particles=True, | ||
| in_place=True, | ||
| ), | ||
| ], | ||
| proxies=[ | ||
| CouplerProxyMappingCfg( | ||
| source="rigid", | ||
| destination="mpm", | ||
| bodies=[BOX_BODY_PATTERN], | ||
| mode="lagged", | ||
| collision_pipeline=None, | ||
| ) | ||
| ], | ||
| iterations=1, | ||
| ) | ||
| return sim_utils.SimulationCfg( | ||
| dt=1.0 / FPS, | ||
| device=args_cli.device, | ||
| gravity=GRAVITY, | ||
| visualizer_cfgs=create_visualizer_cfgs(), | ||
| physics=NewtonCfg(solver_cfg=solver_cfg), | ||
| ) | ||
|
|
||
|
|
||
| def create_scene_cfg(): | ||
| """Create the declarative rigid-box and granular-bed scene.""" | ||
| from isaaclab_newton.assets.mpm_object import MPMObjectCfg | ||
| from isaaclab_newton.sim.spawners.mpm import MPMGridCfg, MPMParticleMaterialCfg | ||
|
|
||
| import isaaclab.sim as sim_utils | ||
| from isaaclab.assets import AssetBaseCfg, RigidObjectCfg, RigidObjectCollectionCfg | ||
| from isaaclab.scene import InteractiveSceneCfg | ||
| from isaaclab.utils.configclass import configclass | ||
|
|
||
| rigid_objects = {} | ||
| for index, (half_extents, mass, offset_xy) in enumerate( | ||
| zip(BOX_HALF_EXTENTS, BOX_MASSES, BOX_OFFSETS_XY, strict=True) | ||
| ): | ||
| rigid_objects[f"box_{index}"] = RigidObjectCfg( | ||
| prim_path=f"{{ENV_REGEX_NS}}/Box_{index}", | ||
| spawn=sim_utils.CuboidCfg( | ||
| size=tuple(2.0 * extent for extent in half_extents), | ||
| rigid_props=sim_utils.RigidBodyPropertiesCfg(), | ||
| mass_props=sim_utils.MassPropertiesCfg(mass=mass), | ||
| collision_props=sim_utils.NewtonCollisionPropertiesCfg(contact_gap=0.1), | ||
| physics_material=sim_utils.NewtonMaterialPropertiesCfg( | ||
| static_friction=0.5, | ||
| dynamic_friction=0.5, | ||
| ), | ||
| ), | ||
| init_state=RigidObjectCfg.InitialStateCfg( | ||
| pos=(offset_xy[0], offset_xy[1], 2.0 + 0.6 * index), | ||
| ), | ||
| ) | ||
|
|
||
| @configclass | ||
| class CoupledSceneCfg(InteractiveSceneCfg): | ||
| """Scene containing dynamic rigid boxes and one Newton MPM object.""" | ||
|
|
||
| ground = AssetBaseCfg( | ||
| prim_path="/World/Ground", | ||
| spawn=sim_utils.GroundPlaneCfg(size=(6.0, 6.0), color=(0.30, 0.30, 0.30)), | ||
| ) | ||
|
|
||
| boxes = RigidObjectCollectionCfg(rigid_objects=rigid_objects) | ||
|
|
||
| sand = MPMObjectCfg( | ||
| prim_path="{ENV_REGEX_NS}/Sand", | ||
| spawn=MPMGridCfg( | ||
| lower=(-1.0, -1.0, 0.0), | ||
| upper=(1.0, 1.0, 0.5), | ||
| voxel_size=args_cli.voxel_size, | ||
| particles_per_cell=PARTICLES_PER_CELL, | ||
| jitter=args_cli.voxel_size / PARTICLES_PER_CELL, | ||
| material=MPMParticleMaterialCfg(density=2500.0, friction=0.75, yield_pressure=1.0e15), | ||
| visual_color=PARTICLE_COLOR, | ||
| ), | ||
| ) | ||
|
|
||
| return CoupledSceneCfg(num_envs=1, env_spacing=0.0) | ||
|
|
||
|
|
||
| def run_simulator(sim, scene) -> None: | ||
| """Run until the viewer closes or the optional step limit is reached.""" | ||
| sim_dt = sim.get_physics_dt() | ||
| step_count = 0 | ||
| while sim.is_headless_or_exist_active_visualizer() and (args_cli.max_steps < 0 or step_count < args_cli.max_steps): | ||
| sim.step(render=False) | ||
| scene.update(sim_dt) | ||
| if sim.is_rendering: | ||
| sim.render() | ||
| step_count += 1 | ||
|
|
||
|
|
||
| def main() -> None: | ||
| """Launch the two-way rigid-MPM coupling demo.""" | ||
| sim_cfg = create_sim_cfg() | ||
| with launch_simulation(sim_cfg, args_cli): | ||
| import isaaclab.sim as sim_utils | ||
| from isaaclab.scene import InteractiveScene | ||
|
|
||
| sim = sim_utils.SimulationContext(sim_cfg) | ||
| sim.set_camera_view(eye=(3.0, -4.0, 2.5), target=(0.0, 0.0, 0.8)) | ||
| scene = InteractiveScene(create_scene_cfg()) | ||
| sim.reset() | ||
| sand = scene["sand"] | ||
| particle_count = sand.num_instances * sand.particles_per_object | ||
| print( | ||
| f"[INFO]: Isaac Lab Newton two-way MPM demo ready. Spawned {particle_count} particles.", | ||
| flush=True, | ||
| ) | ||
| print("[INFO]: Right-click and drag a box in the Newton viewer.", flush=True) | ||
| run_simulator(sim, scene) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.