Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
- Add viewer layer system to overlay multiple solvers/models in supported rendering viewers; call `ViewerBase.activate(layer_id)` to route subsequent `set_model` / `log_state` / `log_*` calls into a named layer, `ViewerBase.set_layer_visible()` to toggle layers independently, and `ViewerBase.set_layer_transform()` to position layers side-by-side. See `example_basic_multi_solver_overlay.py`
- Add `Heightfield.create_from_mesh()` and `newton.utils.rasterize_mesh_to_heightfield()` to build a heightfield collider by ray-casting a `wp.Mesh`, replacing a large static terrain mesh with an equivalent heightfield.
- Add `ViewerBase.camera_speed` to configure keyboard translation speed for interactive viewers. (#3439)
- Add a "Show Ground" visualization toggle (`ViewerBase.show_ground`, default on) to hide or show ground-plane shapes in the viewer.
- Add opt-in DVI forward dynamics to `SolverKamino` through `SolverKamino.Config(dynamics_solver="dvi")`, with sparse and dense execution, DVI-specific diagnostics, and warm-starting. PADMM remains the default.
- Add SDF contact support for convex-hull shapes with mesh-attached SDFs and opt-in SDF contact generation for box shapes.
- Add opt-in filtering of static-static, static-kinematic, and kinematic-kinematic contacts during broad-phase collision detection. Set `CollisionPipeline(include_static_kinematic_pairs=False)` to enable filtering; the default preserves existing contact generation. `Model.shape_contact_pairs` remains an unfiltered superset for direct consumers such as `SolverKamino` and hydroelastic SDF setup.
Expand Down
9 changes: 7 additions & 2 deletions newton/_src/viewer/viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,7 @@ def _init_layer_state(self, layer: Layer) -> None:
layer.show_gaussians = False
layer.show_collision = False
layer.show_visual = True
layer.show_ground = True
layer.show_static = False
layer.show_inertia_boxes = False
layer.show_hydro_contact_surface = False
Expand Down Expand Up @@ -950,7 +951,7 @@ def log_state(self, state: newton.State):

# compute shape transforms and render
for shapes in self._shape_instances.values():
visible = self._should_show_shape(shapes.flags, shapes.static) and not layer_hidden
visible = self._should_show_shape(shapes.flags, shapes.static, shapes.geo_type) and not layer_hidden

if visible:
shapes.update(state, world_offsets=self.world_offsets, layer_xform=self.layer.xform)
Expand Down Expand Up @@ -1918,9 +1919,13 @@ def _hash_geometry(
def _hash_shape(self, geo_hash, shape_static, shape_flags) -> int:
return hash((geo_hash, shape_static, shape_flags))

def _should_show_shape(self, flags: int, is_static: bool) -> bool:
def _should_show_shape(self, flags: int, is_static: bool, geo_type: int | None = None) -> bool:
"""Determine if a shape should be visible based on current settings."""

# A dedicated ground toggle hides plane shapes (e.g. the ground plane).
if geo_type is not None and int(geo_type) == int(newton.GeoType.PLANE) and not self.show_ground:
return False

has_collide_flag = bool(flags & int(newton.ShapeFlags.COLLIDE_SHAPES))
has_visible_flag = bool(flags & int(newton.ShapeFlags.VISIBLE))

Expand Down
2 changes: 1 addition & 1 deletion newton/_src/viewer/viewer_gl.py
Original file line number Diff line number Diff line change
Expand Up @@ -1590,7 +1590,7 @@ def log_state(self, state: nt.State):

layer_hidden = self._layer_force_hidden()
for key, shapes, offset, count in self._packed_groups:
visible = self._should_show_shape(shapes.flags, shapes.static) and not layer_hidden
visible = self._should_show_shape(shapes.flags, shapes.static, shapes.geo_type) and not layer_hidden
colors = shapes.colors if self.model_changed or shapes.colors_changed else None
materials = shapes.materials if self.model_changed else None

Expand Down
1 change: 1 addition & 0 deletions newton/_src/viewer/viewer_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,7 @@ def _render_left_panel(self):
"Wireframe Width (px)", renderer.wireframe_line_width, 0.5, 5.0
)
_changed, viewer.show_visual = imgui.checkbox("Show Visual", viewer.show_visual)
_changed, viewer.show_ground = imgui.checkbox("Show Ground", viewer.show_ground)
_changed, viewer.show_inertia_boxes = imgui.checkbox(
"Show Inertia Boxes", viewer.show_inertia_boxes
)
Expand Down
14 changes: 14 additions & 0 deletions newton/_src/viewer/viewer_rtx.py
Original file line number Diff line number Diff line change
Expand Up @@ -1291,8 +1291,21 @@ def log_state(self, state: newton.State) -> None:
else:
# Render phase: flat arrays (built at end of build phase) handle all shape
# transform updates in a single kernel launch — no per-batch work needed here.
show_ground = self.show_ground
show_ground_changed = show_ground != self._last_show_ground
layer_hidden = self._layer_force_hidden() if show_ground_changed else False
for shapes in self._shape_instances.values():
shapes.colors_changed = False
if show_ground_changed and int(shapes.geo_type) == int(newton.GeoType.PLANE):
qualified = self._qualify(shapes.name)
# Re-derive through the same predicate the build path uses, so
# re-enabling the ground does not override show_visual,
# show_collision, static-shape, or layer rules.
self._pending_instance_visibility[qualified] = (
self._should_show_shape(shapes.flags, shapes.static, shapes.geo_type) and not layer_hidden
)
if show_ground_changed:
self._last_show_ground = show_ground

self._log_gaussian_shapes(state)
self._log_non_shape_state(state)
Expand Down Expand Up @@ -2063,6 +2076,7 @@ def clear_model(self) -> None:

self._last_state = None
self._last_control = None
self._last_show_ground = True

# reset camera
self.camera = Camera(width=self._render_width, height=self._render_height, up_axis=self._up_axis)
Expand Down
Loading