Skip to content

Add Per-Mesh Color and PBR Material Overrides to log_mesh#2628

Merged
eric-heiden merged 2 commits into
newton-physics:mainfrom
christophercrouzet:ccrouzet/per-mesh-props
May 6, 2026
Merged

Add Per-Mesh Color and PBR Material Overrides to log_mesh#2628
eric-heiden merged 2 commits into
newton-physics:mainfrom
christophercrouzet:ccrouzet/per-mesh-props

Conversation

@christophercrouzet

@christophercrouzet christophercrouzet commented Apr 28, 2026

Copy link
Copy Markdown
Member

Description

Extend ViewerBase.log_mesh() with three optional per-mesh material parameters: color (RGB base color used when no texture is supplied), roughness, and metallic. This lets callers tint or restyle individual meshes through the public viewer API without authoring per-vertex colors or building a texture.

The new parameters are wired through every viewer backend (gl, usd, rerun, viser, file, null); the GL backend honors the values via the existing PBR uniforms, while other backends accept the arguments for API parity.

Checklist

  • New or existing tests cover these changes
  • The documentation is up to date with these changes
  • CHANGELOG.md has been updated (if user-facing change)

New feature / API change

import newton

viewer = newton.viewer.ViewerGL()
viewer.log_mesh(
    "/world/widget",
    points=points,
    indices=indices,
    color=(0.85, 0.1, 0.1),
    roughness=0.3,
    metallic=1.0,
)

Summary by CodeRabbit

  • New Features

    • Mesh logging now supports per-mesh RGB color tinting and per-mesh PBR overrides for roughness and metallic when logging meshes, enabling per-mesh appearance control without vertex colors.
  • Documentation

    • Updated mesh logging docs and docstrings to describe the new color, roughness, and metallic parameters, their [0,1] ranges, and semantics.
  • Chores

    • Preserved backward compatibility; cleaned up CHANGELOG formatting.

@coderabbitai

coderabbitai Bot commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: b4323a67-fb75-4066-8560-e15d6485f08f

📥 Commits

Reviewing files that changed from the base of the PR and between f81c0d8 and 17accf2.

📒 Files selected for processing (9)
  • CHANGELOG.md
  • newton/_src/viewer/gl/opengl.py
  • newton/_src/viewer/viewer.py
  • newton/_src/viewer/viewer_file.py
  • newton/_src/viewer/viewer_gl.py
  • newton/_src/viewer/viewer_null.py
  • newton/_src/viewer/viewer_rerun.py
  • newton/_src/viewer/viewer_usd.py
  • newton/_src/viewer/viewer_viser.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • CHANGELOG.md

📝 Walkthrough

Walkthrough

Adds optional per-mesh appearance controls (color tint, roughness, metallic) to Viewer.log_mesh across viewer backends. ViewerGL/Viser store and apply per-mesh color/material; MeshGL writes color/material to vertex attribs at render time. CHANGELOG and docstrings updated.

Changes

Per-mesh appearance API & wiring

Layer / File(s) Summary
Changelog / Notes
CHANGELOG.md
Documents new per-mesh color tint and PBR overrides for ViewerBase.log_mesh().
Public API
newton/_src/viewer/viewer.py
ViewerBase.log_mesh() signature extended with color, roughness, metallic; docstring updated.
Viewer implementations (API surface)
newton/_src/viewer/viewer_gl.py, newton/_src/viewer/viewer_file.py, newton/_src/viewer/viewer_null.py, newton/_src/viewer/viewer_rerun.py, newton/_src/viewer/viewer_usd.py, newton/_src/viewer/viewer_viser.py
log_mesh signatures updated to accept color, roughness, metallic and docstrings expanded. Most backends remain no-ops; ViewerGL and ViewerViser apply/record overrides on mesh objects.
OpenGL rendering wiring
newton/_src/viewer/gl/opengl.py
MeshGL stores self.color/self.material defaults instead of writing GL state at init. MeshGL.render() writes per-mesh values via glVertexAttrib3f(7, ...) and glVertexAttrib4f(8, ...) before draw.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant ViewerGL
  participant MeshGL
  participant OpenGL as GPU
  Caller->>ViewerGL: log_mesh(mesh, texture, color?, roughness?, metallic?)
  ViewerGL->>MeshGL: store mesh.color and mesh.material overrides
  Caller->>ViewerGL: trigger frame/render
  ViewerGL->>MeshGL: MeshGL.render()
  MeshGL->>OpenGL: set vertex attrib 7 (color) and 8 (material)
  MeshGL->>OpenGL: bind VAO / textures and issue draw call
  OpenGL-->>MeshGL: draw completes
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately and specifically describes the main change: adding per-mesh color and PBR material override parameters to the log_mesh method across multiple viewer backends.
Docstring Coverage ✅ Passed Docstring coverage is 90.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@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.

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

1243-1260: Sync Args: docs with the expanded log_mesh signature.

color, roughness, and metallic are now accepted but missing from the method’s documented arguments.

As per coding guidelines: "Follow Google-style docstrings with types in annotations, not docstrings. Use Args: with name: description format."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@newton/_src/viewer/viewer_file.py` around lines 1243 - 1260, Update the
log_mesh docstring Args section to include the new parameters introduced in the
signature: add entries for color, roughness, and metallic (using the
Google-style "param: description" format), and ensure their descriptions match
existing style for other args (e.g., color: Optional RGB tuple for mesh color;
roughness: Optional float controlling surface roughness; metallic: Optional
float controlling metalness). Keep types only in the function signature and not
in the docstring, and leave other argument descriptions unchanged to stay
consistent with the log_mesh function and surrounding docstring style.
newton/_src/viewer/viewer_viser.py (1)

411-429: Add missing Args: entries for new material parameters.

Please document color, roughness, and metallic in the log_mesh docstring (and note backend behavior if they are intentionally ignored here).

As per coding guidelines: "Follow Google-style docstrings with types in annotations, not docstrings. Use Args: with name: description format."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@newton/_src/viewer/viewer_viser.py` around lines 411 - 429, Update the
log_mesh docstring to include Args entries for the new material parameters: add
color, roughness, and metallic using the Google-style "name: description" format
(do not repeat types in the docstring), e.g. describe color as an RGB tuple
applied to the mesh, roughness and metallic as material properties in [0,1];
also state the backend behavior for these fields (e.g., "ignored by viser
backend" or "used by backend to set material properties") so callers know
whether these parameters will affect visualization; ensure the entries reference
the existing parameter names exactly (color, roughness, metallic) and keep the
rest of the docstring unchanged.
newton/_src/viewer/viewer_usd.py (1)

215-233: Document the new log_mesh parameters in Args:.

color, roughness, and metallic were added to the signature, but the Args: section does not describe them yet.

As per coding guidelines: "Follow Google-style docstrings with types in annotations, not docstrings. Use Args: with name: description format."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@newton/_src/viewer/viewer_usd.py` around lines 215 - 233, The Args section of
the docstring for log_mesh (the function with parameters color, roughness,
metallic) is missing descriptions for the newly added parameters; update the
Args: block to add lines for color: optional RGB tuple to tint the mesh,
roughness: optional float controlling PBR roughness, and metallic: optional
float controlling PBR metallicity, following the existing Google-style "name:
description" format and keeping types only in the signature.
newton/_src/viewer/viewer_rerun.py (1)

218-236: Keep the Args: block in sync with the new parameters.

The newly added color, roughness, and metallic parameters should be documented in this method’s docstring.

As per coding guidelines: "Follow Google-style docstrings with types in annotations, not docstrings. Use Args: with name: description format."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@newton/_src/viewer/viewer_rerun.py` around lines 218 - 236, The docstring
Args: block for the mesh-logging method is out of sync—add entries for the new
parameters color, roughness, and metallic using the Google-style "name:
description" format (do not repeat types); update the existing Args: section in
the same method docstring to include lines like "color: Description of RGB tuple
or None", "roughness: Description of optional roughness value", and "metallic:
Description of optional metallic value", ensuring the parameter names match the
function signature and keeping descriptions concise; leave type annotations to
the function signature and do not add types in the docstring.
newton/_src/viewer/viewer_null.py (1)

68-86: Update docstring Args: for the new signature.

Please add entries for color, roughness, and metallic so the no-op backend API docs remain complete.

As per coding guidelines: "Follow Google-style docstrings with types in annotations, not docstrings. Use Args: with name: description format."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@newton/_src/viewer/viewer_null.py` around lines 68 - 86, Update the docstring
for the no-op mesh method (the function with parameters color, roughness,
metallic — locate the method in viewer_null.py that accepts name, points,
indices, normals, uvs, texture, color, hidden, backface_culling, roughness,
metallic) to include Args entries for color, roughness, and metallic using the
Google-style "Args:" format (name: description) and do not include types in the
docstring; e.g., add lines describing color (optional RGB tuple to tint the
mesh), roughness (optional float controlling surface roughness), and metallic
(optional float controlling metallic property) alongside the existing entries
for name, points, indices, normals, uvs, texture, hidden, and backface_culling.
newton/_src/viewer/viewer_gl.py (1)

742-751: Validate color/PBR override inputs before applying them.

At Line 743, tuple indexing assumes exactly 3 channels and currently fails with a generic IndexError for malformed inputs; roughness/metallic are also documented as [0, 1] but not validated.

Proposed hardening patch
         if color is not None:
+            if len(color) != 3:
+                raise ValueError("color must be an RGB tuple of length 3")
+            if any((c < 0.0 or c > 1.0) for c in color):
+                raise ValueError("color values must be in [0, 1]")
             self.objects[name].color = (float(color[0]), float(color[1]), float(color[2]))
 
         if roughness is not None or metallic is not None:
             r, m, c, t = self.objects[name].material
             if roughness is not None:
+                if roughness < 0.0 or roughness > 1.0:
+                    raise ValueError("roughness must be in [0, 1]")
                 r = float(roughness)
             if metallic is not None:
+                if metallic < 0.0 or metallic > 1.0:
+                    raise ValueError("metallic must be in [0, 1]")
                 m = float(metallic)
             self.objects[name].material = (r, m, c, t)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@newton/_src/viewer/viewer_gl.py` around lines 742 - 751, Validate inputs
before assigning to self.objects[name].color and self.objects[name].material:
check that color is a sequence with at least 3 numeric entries (convert to
float) and either raise a clear ValueError or skip assignment for malformed
colors; for roughness and metallic validate they are numeric and clamp or reject
values outside [0,1] before updating r and m (use the existing r,m,c,t tuple
unpacking and reassign self.objects[name].material only after validation).
Ensure errors include the object name to aid debugging.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@newton/_src/viewer/viewer_file.py`:
- Around line 1243-1260: Update the log_mesh docstring Args section to include
the new parameters introduced in the signature: add entries for color,
roughness, and metallic (using the Google-style "param: description" format),
and ensure their descriptions match existing style for other args (e.g., color:
Optional RGB tuple for mesh color; roughness: Optional float controlling surface
roughness; metallic: Optional float controlling metalness). Keep types only in
the function signature and not in the docstring, and leave other argument
descriptions unchanged to stay consistent with the log_mesh function and
surrounding docstring style.

In `@newton/_src/viewer/viewer_gl.py`:
- Around line 742-751: Validate inputs before assigning to
self.objects[name].color and self.objects[name].material: check that color is a
sequence with at least 3 numeric entries (convert to float) and either raise a
clear ValueError or skip assignment for malformed colors; for roughness and
metallic validate they are numeric and clamp or reject values outside [0,1]
before updating r and m (use the existing r,m,c,t tuple unpacking and reassign
self.objects[name].material only after validation). Ensure errors include the
object name to aid debugging.

In `@newton/_src/viewer/viewer_null.py`:
- Around line 68-86: Update the docstring for the no-op mesh method (the
function with parameters color, roughness, metallic — locate the method in
viewer_null.py that accepts name, points, indices, normals, uvs, texture, color,
hidden, backface_culling, roughness, metallic) to include Args entries for
color, roughness, and metallic using the Google-style "Args:" format (name:
description) and do not include types in the docstring; e.g., add lines
describing color (optional RGB tuple to tint the mesh), roughness (optional
float controlling surface roughness), and metallic (optional float controlling
metallic property) alongside the existing entries for name, points, indices,
normals, uvs, texture, hidden, and backface_culling.

In `@newton/_src/viewer/viewer_rerun.py`:
- Around line 218-236: The docstring Args: block for the mesh-logging method is
out of sync—add entries for the new parameters color, roughness, and metallic
using the Google-style "name: description" format (do not repeat types); update
the existing Args: section in the same method docstring to include lines like
"color: Description of RGB tuple or None", "roughness: Description of optional
roughness value", and "metallic: Description of optional metallic value",
ensuring the parameter names match the function signature and keeping
descriptions concise; leave type annotations to the function signature and do
not add types in the docstring.

In `@newton/_src/viewer/viewer_usd.py`:
- Around line 215-233: The Args section of the docstring for log_mesh (the
function with parameters color, roughness, metallic) is missing descriptions for
the newly added parameters; update the Args: block to add lines for color:
optional RGB tuple to tint the mesh, roughness: optional float controlling PBR
roughness, and metallic: optional float controlling PBR metallicity, following
the existing Google-style "name: description" format and keeping types only in
the signature.

In `@newton/_src/viewer/viewer_viser.py`:
- Around line 411-429: Update the log_mesh docstring to include Args entries for
the new material parameters: add color, roughness, and metallic using the
Google-style "name: description" format (do not repeat types in the docstring),
e.g. describe color as an RGB tuple applied to the mesh, roughness and metallic
as material properties in [0,1]; also state the backend behavior for these
fields (e.g., "ignored by viser backend" or "used by backend to set material
properties") so callers know whether these parameters will affect visualization;
ensure the entries reference the existing parameter names exactly (color,
roughness, metallic) and keep the rest of the docstring unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 670fb1e3-e0b8-4e99-b946-0a4795376e02

📥 Commits

Reviewing files that changed from the base of the PR and between 98dcd03 and 230e928.

📒 Files selected for processing (9)
  • CHANGELOG.md
  • newton/_src/viewer/gl/opengl.py
  • newton/_src/viewer/viewer.py
  • newton/_src/viewer/viewer_file.py
  • newton/_src/viewer/viewer_gl.py
  • newton/_src/viewer/viewer_null.py
  • newton/_src/viewer/viewer_rerun.py
  • newton/_src/viewer/viewer_usd.py
  • newton/_src/viewer/viewer_viser.py

@codecov

codecov Bot commented Apr 28, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 13 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 0.00% 9 Missing ⚠️
newton/_src/viewer/gl/opengl.py 0.00% 4 Missing ⚠️

📢 Thoughts on this report? Let us know!

@eric-heiden

Copy link
Copy Markdown
Member

⚪ This is a useful extension to log_mesh for per-mesh appearance control.

The main issue is that the new public API shape can break existing positional callers, so the parameter order needs to stay backward compatible.

Comment thread newton/_src/viewer/viewer.py Outdated

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@newton/_src/viewer/viewer_viser.py`:
- Around line 413-415: The docstring for ViewerViser.log_mesh says the color
parameter is used when no texture is provided but the untextured path currently
hardcodes color=(180,180,180); update ViewerViser.log_mesh to honor the passed
color/roughness/metallic: when texture is None use the provided color (convert
if needed to the renderer's expected range), and apply roughness and metallic if
not None instead of forcing defaults; ensure the branch that creates the
untextured material uses the function/class that builds materials in this file
(log_mesh's material/mesh creation code paths) so the public parameters actually
affect rendering.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: b1e0230f-f39a-4468-a189-69529f861e5d

📥 Commits

Reviewing files that changed from the base of the PR and between 230e928 and bb5a447.

📒 Files selected for processing (9)
  • CHANGELOG.md
  • newton/_src/viewer/gl/opengl.py
  • newton/_src/viewer/viewer.py
  • newton/_src/viewer/viewer_file.py
  • newton/_src/viewer/viewer_gl.py
  • newton/_src/viewer/viewer_null.py
  • newton/_src/viewer/viewer_rerun.py
  • newton/_src/viewer/viewer_usd.py
  • newton/_src/viewer/viewer_viser.py
✅ Files skipped from review due to trivial changes (3)
  • newton/_src/viewer/viewer_usd.py
  • newton/_src/viewer/viewer_null.py
  • CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • newton/_src/viewer/gl/opengl.py
  • newton/_src/viewer/viewer_rerun.py

Comment thread newton/_src/viewer/viewer_viser.py
@christophercrouzet christophercrouzet force-pushed the ccrouzet/per-mesh-props branch from bb5a447 to f81c0d8 Compare May 5, 2026 22:23

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@newton/_src/viewer/viewer_gl.py`:
- Around line 761-770: When assigning color and material scalars in viewer_gl
(around the block that sets self.objects[name].color and
self.objects[name].material), validate inputs: ensure color is an iterable of
length 3 with numeric elements in [0,1] and raise TypeError/ValueError if not;
for roughness and metallic ensure they are numeric and within [0,1] before
casting to float and assigning (raise ValueError/TypeError on invalid values);
keep the existing unpacking of the material tuple (r, m, c, t) and only replace
r/m after validation so malformed inputs fail fast and preserve previous
material state on error.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: b3edf785-437b-4d82-8645-152d1ecf97eb

📥 Commits

Reviewing files that changed from the base of the PR and between bb5a447 and f81c0d8.

📒 Files selected for processing (9)
  • CHANGELOG.md
  • newton/_src/viewer/gl/opengl.py
  • newton/_src/viewer/viewer.py
  • newton/_src/viewer/viewer_file.py
  • newton/_src/viewer/viewer_gl.py
  • newton/_src/viewer/viewer_null.py
  • newton/_src/viewer/viewer_rerun.py
  • newton/_src/viewer/viewer_usd.py
  • newton/_src/viewer/viewer_viser.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • newton/_src/viewer/viewer.py

Comment thread newton/_src/viewer/viewer_gl.py
@christophercrouzet christophercrouzet force-pushed the ccrouzet/per-mesh-props branch from f81c0d8 to 17accf2 Compare May 6, 2026 19:31

@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.

Thanks!

@eric-heiden eric-heiden added this pull request to the merge queue May 6, 2026
Merged via the queue into newton-physics:main with commit bc4f19b May 6, 2026
35 of 36 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.

2 participants