Skip to content

ViewerGL: Batching Capsules with Different Sizes#1469

Merged
eric-heiden merged 3 commits into
newton-physics:mainfrom
jumyungc:viewergl-capsule
Jan 28, 2026
Merged

ViewerGL: Batching Capsules with Different Sizes#1469
eric-heiden merged 3 commits into
newton-physics:mainfrom
jumyungc:viewergl-capsule

Conversation

@jumyungc

@jumyungc jumyungc commented Jan 28, 2026

Copy link
Copy Markdown
Member

Description

Previously, capsule-based instancing was used, which created separate instances whenever the capsule size changed. This change allows batching capsules of different sizes.

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

    • Added capsule geometry rendering using instanced body+end meshes with automatic batching across per-instance scales.
    • Introduced backend extensibility for specialized capsule rendering and improved geometry-type propagation for per-batch decisions.
  • Tests

    • Added tests validating capsule batching, per-instance scale handling, cached-geometry reuse, and correct routing of capsule vs. non-capsule logging.

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

Signed-off-by: JC <jumyungc@nvidia.com>
@jumyungc jumyungc self-assigned this Jan 28, 2026
@coderabbitai

coderabbitai Bot commented Jan 28, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Dispatches capsule geometries to a new capsule-specific rendering path, adds a backend hook log_capsules(), propagates geometry-type via ShapeInstances.geo_type, and implements GPU Warp kernels and batching updates to render capsules as instanced cylinder bodies + sphere caps.

Changes

Cohort / File(s) Summary
Core viewer API
newton/_src/viewer/viewer.py
Added log_capsules(...) hook on ViewerBase (defaults to log_instances) and added geo_type field to ViewerBase.ShapeInstances for per-batch geometry-type routing.
GL viewer + instancing
newton/_src/viewer/viewer_gl.py
Added Warp kernels (_capsule_duplicate_vec3/vec4, _capsule_build_body_scales, _capsule_build_cap_xforms_and_scales), capsule-aware _hash_geometry, per-instance scale conversion in set_model(), and log_capsules() implementations to emit capsule bodies and caps as instanced meshes.
Tests
newton/tests/test_viewer_geometry_batching.py
New tests and _ViewerGeometryBatchingProbe validating capsule batching across scales, geometry cache behavior, per-instance scale rewriting, and log_state() dispatch to log_capsules.

Sequence Diagrams

sequenceDiagram
    participant Client
    participant ViewerBase
    participant Batching
    participant GPU
    participant Renderer

    Client->>ViewerBase: log_state(model,...)
    ViewerBase->>Batching: group shapes (uses geo_type)
    alt capsule batch
        Batching->>GPU: _capsule_build_body_scales(shape_scale, indices)
        GPU-->>Batching: body_scales (r,r,half_h)
        Batching->>GPU: _capsule_build_cap_xforms_and_scales(xforms, scales)
        GPU-->>Batching: cap_xforms, cap_scales
        Batching->>GPU: _capsule_duplicate_vec3/vec4(colors,materials)
        GPU-->>Batching: duplicated attributes
        Batching->>Renderer: emit capsule_body instancer + capsule_caps instancer
        Renderer->>Renderer: draw cylinder bodies and sphere caps (instanced)
    else non-capsule
        Batching->>Renderer: emit standard instancer data
        Renderer->>Renderer: draw standard instanced geometry
    end
    Renderer-->>Client: frame rendered
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • eric-heiden
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.46% 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 clearly and specifically describes the main change: enabling batching of capsules with different sizes in ViewerGL, which is the core objective of the PR.

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

✨ Finishing touches
  • 📝 Generate docstrings

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

codecov Bot commented Jan 28, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 17.91045% with 55 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_gl.py 5.26% 54 Missing ⚠️
newton/_src/viewer/viewer.py 90.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@newton/_src/viewer/viewer_gl.py`:
- Around line 416-497: The override method log_capsules has an unused parameter
mesh causing a Ruff ARG002 warning; rename the parameter to _mesh in the
log_capsules signature (and update any internal references if present) so the
unused argument is intentionally ignored, leaving all other logic (including
calls to log_instances and creation of sphere_mesh/cylinder_mesh, cap_xforms,
cap_scales, cap_colors, cap_materials) unchanged.

In `@newton/tests/test_viewer_geometry_batching.py`:
- Around line 69-71: The test stub method log_instances currently accepts
parameters (name, mesh, xforms, scales, colors, materials, hidden=False) but
doesn't use them, triggering Ruff ARG002; update the signature of log_instances
to silence unused-argument warnings by either prefixing unused parameter names
with an underscore (e.g., _name, _mesh, etc.) or replacing the parameters with a
catch-all (*args, **kwargs), and keep the body as self.log_instances_calls += 1
so the call count remains unchanged.

Comment thread newton/_src/viewer/viewer_gl.py
Comment thread newton/tests/test_viewer_geometry_batching.py Outdated
Comment thread newton/_src/viewer/viewer_gl.py
Comment thread newton/_src/viewer/viewer_gl.py Outdated

@eric-heiden eric-heiden left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why do capsules have the scale (r, r, half_height) here? They should be (r, h, 0) (the last entry is ignored).

@jumyungc

jumyungc commented Jan 28, 2026

Copy link
Copy Markdown
Member Author

Why do capsules have the scale (r, r, half_height) here? They should be (r, h, 0) (the last entry is ignored).

Thank you @eric-heiden for the feedback!

As you mentioned, model-side capsule shape_scale is stored as (radius, half_height, 0).
But for better batching in ViewerGL (instancing different-sized capsules together), capsules are now rendered using one shared unit cylinder (body) and one shared unit sphere (cap), with per-instance transforms/scales.

So the (cylinder) body’s per-instance scale in the viewer is (radius, radius, half_height), following the viewer's cylinder convention.

@eric-heiden

Copy link
Copy Markdown
Member

Why do capsules have the scale (r, r, half_height) here? They should be (r, h, 0) (the last entry is ignored).

Thank you @eric-heiden for the feedback!

As you mentioned, model-side capsule shape_scale is stored as (radius, half_height, 0). But for better batching in ViewerGL (instancing different-sized capsules together), capsules are now rendered using one shared unit cylinder (body) and one shared unit sphere (cap), with per-instance transforms/scales.

So the (cylinder) body’s per-instance scale in the viewer is (radius, radius, half_height), following the viewer's cylinder convention.

Thanks @jumyungc for clarifying and adding these comments! I can see the scale refers to the xyz mesh scaling now.

@eric-heiden eric-heiden added this pull request to the merge queue Jan 28, 2026
Merged via the queue into newton-physics:main with commit 12e796d Jan 28, 2026
22 checks passed
@jumyungc jumyungc deleted the viewergl-capsule branch January 28, 2026 23:22
@coderabbitai coderabbitai Bot mentioned this pull request Feb 17, 2026
4 tasks
mmacklin pushed a commit to mmacklin/newton that referenced this pull request Apr 7, 2026
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.

Slow capsule visualization when different capsule dimensions are used.

2 participants