Skip to content

Conversation

@jvonmuralt
Copy link
Member

@jvonmuralt jvonmuralt commented Jan 8, 2026

Description

Newton Migration Guide

Please ensure the migration guide for warp.sim users is up-to-date with the changes made in this PR.

  • The migration guide in docs/migration.rst is up-to date

Before your PR is "Ready for review"

  • Necessary tests have been added and new examples are tested (see newton/tests/test_examples.py)
  • Documentation is up-to-date
  • Code passes formatting and linting checks with pre-commit run -a

Summary by CodeRabbit

  • New Features

    • Viewer can now limit how many worlds are rendered (select a subset) to improve performance; a corresponding runtime option was added.
    • Examples updated to demonstrate limiting rendered worlds.
  • Documentation

    • Visualization guide updated with usage example and explanation of the new rendering limit option.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 8, 2026

📝 Walkthrough

Walkthrough

Introduces a per-world rendering cap via an optional max_worlds parameter to set_model(); adds _should_render_world() and _get_render_world_count() helpers; applies filtering to world-offsets, shape/SDF isomesh, and inertia-box population; propagates parameter through viewer subclasses and examples/CLI.

Changes

Cohort / File(s) Summary
Core viewer implementation
newton/_src/viewer/viewer.py
Added max_worlds attribute and max_worlds parameter to set_model(); new helpers _should_render_world() and _get_render_world_count(); replaced direct world-count usage and added filtering in set_world_offsets(), _auto_compute_world_offsets(), _populate_shapes(), _populate_sdf_isomesh_instances(), and _populate_inertia_boxes() to honor the cap.
Viewer subclasses
newton/_src/viewer/viewer_file.py, newton/_src/viewer/viewer_gl.py
set_model() signatures now accept optional max_worlds and forward it to super().set_model(model, max_worlds=max_worlds); viewer_file also sets self._model_recorded = True after recording.
Examples & CLI
newton/examples/__init__.py, newton/examples/selection/example_selection_cartpole.py
Added --max-worlds CLI option; examples accept max_worlds and pass it to viewer.set_model(...), and example constructor updated to include max_worlds.
Docs
docs/guide/visualization.rst
Documentation updated to mention the new max_worlds parameter and show usage example viewer.set_model(model, max_worlds=4).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 70.59% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and clearly summarizes the main change: adding a max_worlds parameter to limit the number of worlds rendered in Newton visualizers.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5763ca9 and 91118bd.

📒 Files selected for processing (2)
  • docs/guide/visualization.rst
  • newton/examples/selection/example_selection_cartpole.py
✅ Files skipped from review due to trivial changes (1)
  • docs/guide/visualization.rst
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-08-25T21:41:45.795Z
Learnt from: dylanturpin
Repo: newton-physics/newton PR: 634
File: newton/tests/test_examples.py:329-333
Timestamp: 2025-08-25T21:41:45.795Z
Learning: Newton examples use a centralized CLI argument parsing system in newton/examples/__init__.py. The create_parser() function defines common arguments like --device, --viewer, --output-path, and --num-frames, while init(parser) creates viewers based on parsed arguments. Individual example scripts don't need to define these flags themselves - they inherit them from the centralized system via the example_map and runpy execution.

Applied to files:

  • newton/examples/selection/example_selection_cartpole.py
📚 Learning: 2025-12-06T19:10:24.360Z
Learnt from: vastsoun
Repo: newton-physics/newton PR: 1019
File: newton/_src/solvers/kamino/examples/sim/example_sim_basics_box_on_plane.py:322-371
Timestamp: 2025-12-06T19:10:24.360Z
Learning: In Newton Kamino examples under newton/_src/solvers/kamino/examples/sim, CLI arguments parsed via argparse (including flags like --test, --device, --headless, etc.) are passed as a complete args object to newton.examples.run(example, args). The run function internally consumes these flags to control execution behavior, so flags may appear "unused" in the example script itself even though they are actively used by the framework.

Applied to files:

  • newton/examples/selection/example_selection_cartpole.py
📚 Learning: 2025-12-12T08:45:43.428Z
Learnt from: nvtw
Repo: newton-physics/newton PR: 1221
File: newton/examples/example_sdf.py:277-287
Timestamp: 2025-12-12T08:45:43.428Z
Learning: In Newtown (Newton) example code, specifically files under newton/examples, computing contacts once per frame and reusing them across all substeps is an intentional design choice, not a bug. Reviewers should verify that contacts are computed before the substep loop and reused for every substep within the same frame. This pattern reduces redundant work and preserves frame-consistency; do not flag as a regression unless the behavior is changed for correctness or performance reasons.

Applied to files:

  • newton/examples/selection/example_selection_cartpole.py
🧬 Code graph analysis (1)
newton/examples/selection/example_selection_cartpole.py (3)
newton/_src/viewer/viewer_file.py (1)
  • set_model (59-65)
newton/_src/viewer/viewer.py (1)
  • set_model (121-142)
newton/_src/viewer/viewer_gl.py (1)
  • set_model (188-202)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Run GPU Tests / Run GPU Unit Tests on AWS EC2
  • GitHub Check: Run GPU Benchmarks / Run GPU Benchmarks on AWS EC2
🔇 Additional comments (4)
newton/examples/selection/example_selection_cartpole.py (4)

23-24: LGTM!

The updated command hint correctly documents the new --max-worlds argument and provides a clear usage example.


59-59: LGTM!

The new max_worlds parameter with a sensible default of None (render all worlds) is a clean addition to the constructor signature.


114-115: LGTM!

The max_worlds parameter is correctly propagated to the viewer's set_model() method, which aligns with the viewer interface in newton/_src/viewer/viewer.py.


239-239: The --max-worlds argument is already properly defined in the centralized parser at newton/examples/__init__.py (lines 341-345) with type=int, default=None. The code at line 239 will not produce an AttributeError at runtime. No changes needed.

Likely an incorrect or invalid review comment.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link

codecov bot commented Jan 8, 2026

Codecov Report

❌ Patch coverage is 62.96296% with 10 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
newton/_src/viewer/viewer.py 65.21% 8 Missing ⚠️
newton/_src/viewer/viewer_file.py 50.00% 1 Missing ⚠️
newton/_src/viewer/viewer_gl.py 50.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
newton/_src/viewer/viewer.py (1)

1162-1193: Critical: Fix incorrect arguments in inertia box batch.add() call.

Line 1192 passes only 6 arguments to batch.add(), but the method signature (line 757) expects 7. This causes body_world[body] to be used as shape_index instead of world, leaving world to default to -1.

Comparing with correct usage:

  • Line 990 (shapes): batch.add(parent, xform, scale, color, material, s, shape_world[s])
  • Line 1110 (SDF isomesh): batch.add(parent, xform, scale, color, material, s, shape_world[s])
  • Line 1192 (inertia boxes): batch.add(parent, xform, scale, color, material, body_world[body])
🐛 Proposed fix
             # add render instance
-            batch.add(parent, xform, scale, color, material, body_world[body])
+            batch.add(parent, xform, scale, color, material, body, body_world[body])

This ensures the body index is passed as shape_index and the world index as world, matching the pattern used for shapes and SDF isomeshes.

🧹 Nitpick comments (1)
newton/_src/viewer/viewer.py (1)

121-134: Add input validation for max_worlds parameter.

The parameter lacks validation for invalid values. Consider adding a check to ensure max_worlds is positive when provided:

♻️ Proposed validation
     def set_model(self, model, max_worlds: int | None = None):
         """
         Set the model to be visualized.
 
         Args:
             model: The Newton model to visualize.
             max_worlds: Maximum number of worlds to render (None = all).
                         Useful for performance when training with many environments.
         """
         if self.model is not None:
             raise RuntimeError("Viewer set_model() can be called only once.")
+        
+        if max_worlds is not None and max_worlds <= 0:
+            raise ValueError(f"max_worlds must be positive, got {max_worlds}")
 
         self.model = model
         self.max_worlds = max_worlds
📜 Review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9bbdcbf and 5763ca9.

📒 Files selected for processing (5)
  • newton/_src/viewer/viewer.py
  • newton/_src/viewer/viewer_file.py
  • newton/_src/viewer/viewer_gl.py
  • newton/examples/__init__.py
  • newton/examples/selection/example_selection_cartpole.py
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2025-08-25T21:41:45.795Z
Learnt from: dylanturpin
Repo: newton-physics/newton PR: 634
File: newton/tests/test_examples.py:329-333
Timestamp: 2025-08-25T21:41:45.795Z
Learning: Newton examples use a centralized CLI argument parsing system in newton/examples/__init__.py. The create_parser() function defines common arguments like --device, --viewer, --output-path, and --num-frames, while init(parser) creates viewers based on parsed arguments. Individual example scripts don't need to define these flags themselves - they inherit them from the centralized system via the example_map and runpy execution.

Applied to files:

  • newton/examples/__init__.py
  • newton/examples/selection/example_selection_cartpole.py
📚 Learning: 2025-12-06T19:10:24.360Z
Learnt from: vastsoun
Repo: newton-physics/newton PR: 1019
File: newton/_src/solvers/kamino/examples/sim/example_sim_basics_box_on_plane.py:322-371
Timestamp: 2025-12-06T19:10:24.360Z
Learning: In Newton Kamino examples under newton/_src/solvers/kamino/examples/sim, CLI arguments parsed via argparse (including flags like --test, --device, --headless, etc.) are passed as a complete args object to newton.examples.run(example, args). The run function internally consumes these flags to control execution behavior, so flags may appear "unused" in the example script itself even though they are actively used by the framework.

Applied to files:

  • newton/examples/__init__.py
  • newton/examples/selection/example_selection_cartpole.py
📚 Learning: 2025-12-12T08:45:43.428Z
Learnt from: nvtw
Repo: newton-physics/newton PR: 1221
File: newton/examples/example_sdf.py:277-287
Timestamp: 2025-12-12T08:45:43.428Z
Learning: In Newtown (Newton) example code, specifically files under newton/examples, computing contacts once per frame and reusing them across all substeps is an intentional design choice, not a bug. Reviewers should verify that contacts are computed before the substep loop and reused for every substep within the same frame. This pattern reduces redundant work and preserves frame-consistency; do not flag as a regression unless the behavior is changed for correctness or performance reasons.

Applied to files:

  • newton/examples/__init__.py
  • newton/examples/selection/example_selection_cartpole.py
📚 Learning: 2025-12-12T08:46:21.381Z
Learnt from: nvtw
Repo: newton-physics/newton PR: 1221
File: newton/examples/example_sdf.py:189-191
Timestamp: 2025-12-12T08:46:21.381Z
Learning: In Newton, SDF data structures are shared across replicated world instances (e.g., when using ModelBuilder.replicate()). Therefore, the memory cost of SDF generation scales with sdf_max_resolution but does not scale with the number of worlds. When reviewing or modifying newton/examples/example_sdf.py (and similar example scripts), verify that SDF memory usage is controlled by sdf_max_resolution and not by the count of replicated worlds, and document or justify any changes to sdf_max_resolution to manage memory and performance.

Applied to files:

  • newton/examples/__init__.py
📚 Learning: 2025-08-20T18:02:36.099Z
Learnt from: eric-heiden
Repo: newton-physics/newton PR: 587
File: newton/_src/sim/builder.py:656-661
Timestamp: 2025-08-20T18:02:36.099Z
Learning: In Newton physics, collisions between shapes with body index -1 (world-attached/global shapes) are automatically skipped by the collision system, so no manual collision filter pairs need to be added between global shapes from different builders.

Applied to files:

  • newton/_src/viewer/viewer.py
🧬 Code graph analysis (3)
newton/_src/viewer/viewer_gl.py (2)
newton/_src/viewer/viewer.py (1)
  • set_model (121-142)
newton/_src/viewer/viewer_file.py (1)
  • set_model (59-65)
newton/_src/viewer/viewer_file.py (2)
newton/_src/viewer/viewer.py (1)
  • set_model (121-142)
newton/_src/viewer/viewer_gl.py (1)
  • set_model (188-202)
newton/_src/viewer/viewer.py (3)
newton/_src/viewer/viewer_file.py (1)
  • set_model (59-65)
newton/_src/viewer/viewer_gl.py (1)
  • set_model (188-202)
newton/_src/sim/builder.py (1)
  • body_count (976-980)
🪛 Ruff (0.14.10)
newton/_src/viewer/viewer.py

131-131: Avoid specifying long messages outside the exception class

(TRY003)

⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: run-newton-tests / newton-unittests (windows-latest)
🔇 Additional comments (9)
newton/examples/selection/example_selection_cartpole.py (2)

58-58: LGTM - Clean parameter threading.

The max_worlds parameter is correctly added to the Example initialization and properly forwarded to the viewer. The None default maintains backward compatibility.

Also applies to: 113-113


238-238: No action needed. Both args.num_worlds and args.max_worlds are properly defined: --num-worlds is added by this example file (lines 242-247), and --max-worlds is provided by the centralized parser in newton/examples/__init__.py. The code correctly uses both arguments.

Likely an incorrect or invalid review comment.

newton/examples/__init__.py (1)

340-345: LGTM - CLI argument properly defined.

The --max-worlds argument is correctly added to the centralized parser with appropriate type, default, and help text. This satisfies the dependency from example files.

newton/_src/viewer/viewer_gl.py (1)

188-196: LGTM - Correct parameter propagation.

The max_worlds parameter is properly added to the signature, documented, and forwarded to the base class. The implementation correctly maintains the override pattern.

newton/_src/viewer/viewer_file.py (1)

59-61: LGTM - Consistent with other viewer subclasses.

The parameter forwarding matches the pattern used in ViewerGL. Implementation is correct.

newton/_src/viewer/viewer.py (4)

144-158: LGTM - Well-designed helper methods.

The filtering logic correctly handles:

  • Global entities (world_idx == -1) are always rendered
  • Proper bounds checking with min() to avoid over-counting
  • Clear separation of concerns between should-render check and count calculation

902-904: LGTM - Efficient filtering placement.

The filtering is applied early in the loop before expensive geometry operations, which is the correct optimization.


1044-1046: LGTM - Consistent filtering across visualization types.

The filtering is correctly applied to SDF isomesh instances, maintaining consistency with the regular shape filtering.


212-212: LGTM - Correct usage of helper method.

The _get_render_world_count() helper is appropriately used to ensure world offsets are only computed for worlds that will actually be rendered, maintaining consistency with the filtering logic.

Also applies to: 280-280

@jvonmuralt jvonmuralt linked an issue Jan 8, 2026 that may be closed by this pull request
@jvonmuralt jvonmuralt marked this pull request as ready for review January 9, 2026 10:45
@preist-nvidia
Copy link
Member

@mzamoramora-nvidia can you please review?

@mzamoramora-nvidia mzamoramora-nvidia self-requested a review January 9, 2026 14:36
Copy link
Member

@mzamoramora-nvidia mzamoramora-nvidia left a comment

Choose a reason for hiding this comment

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

@jvonmuralt Thanks for the contribution. It's nice that it works even for the usd viewer.

It would be good to add a note about this argument in the documentation (docs/guide/visualization.rst), so that people can know about this feature from the beginning.

And/or maybe update the execution command in examples_selection_cartpole with small explanation of the argument. Something like:

# To limit the number of worlds to render use the max-worlds argument. 
# Command: python -m newton.examples selection_cartpole --num-worlds 16 --max-worlds 8

Copy link
Member

@eric-heiden eric-heiden left a comment

Choose a reason for hiding this comment

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

Thanks, LGTM!

@eric-heiden eric-heiden added this pull request to the merge queue Jan 12, 2026
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Jan 12, 2026
@eric-heiden eric-heiden merged commit f8ed713 into newton-physics:main Jan 13, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Limit number of worlds shown in Newton visualizers

4 participants