Skip to content

Commit 34ef42d

Browse files
committed
init bug fix for stale renderer images after reset w/o kit viz
1 parent 408c312 commit 34ef42d

7 files changed

Lines changed: 36 additions & 30 deletions

File tree

source/isaaclab/isaaclab/envs/common.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class ViewerCfg:
3838
"""
3939

4040
origin_type: Literal["world", "env", "asset_root", "asset_body"] = "world"
41-
"""The frame in which the camera eye and lookat are defined in. Default is "world".
41+
"""The frame in which the camera position (eye) and target (lookat) are defined in. Default is "world".
4242
4343
Available options are:
4444

source/isaaclab/isaaclab/envs/direct_marl_env.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,7 @@ def _init_sim(self, render_mode: str | None = None, **kwargs):
152152
# non-rendering modes.
153153
# Initialize when GUI is available OR when visualizers are active (headless rendering)
154154
# ViewerCfg camera updates are applied through renderer camera control.
155-
has_visualizers = bool(self.sim.get_setting("/isaaclab/visualizer/types")) or bool(
156-
self.sim.get_setting("/isaaclab/video/auto_start_kit")
157-
)
155+
has_visualizers = self.sim.has_active_visualizers()
158156
if self.sim.has_gui or has_visualizers:
159157
self.viewport_camera_controller = ViewportCameraController(self, self.cfg.viewer)
160158
else:
@@ -524,10 +522,7 @@ def render(self, recompute: bool = False) -> np.ndarray | None:
524522
return None
525523
elif self.render_mode == "rgb_array":
526524
# check that if any render could have happened
527-
has_visualizers = bool(self.sim.get_setting("/isaaclab/visualizer/types")) or bool(
528-
self.sim.get_setting("/isaaclab/video/auto_start_kit")
529-
)
530-
if not (self.sim.has_gui or self.sim.has_offscreen_render or has_visualizers):
525+
if not self.sim.can_render_rgb_array():
531526
raise RuntimeError(
532527
f"Cannot render '{self.render_mode}' - no GUI and offscreen rendering not enabled."
533528
" If running headless, make sure --enable_cameras is set."

source/isaaclab/isaaclab/envs/direct_rl_env.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,7 @@ def _init_sim(self, render_mode: str | None = None, **kwargs):
157157
# non-rendering modes.
158158
# Initialize when GUI is available OR when visualizers are active (headless rendering)
159159
# ViewerCfg camera updates are applied through renderer camera control.
160-
has_visualizers = bool(self.sim.get_setting("/isaaclab/visualizer/types")) or bool(
161-
self.sim.get_setting("/isaaclab/video/auto_start_kit")
162-
)
160+
has_visualizers = self.sim.has_active_visualizers()
163161
if self.sim.has_gui or has_visualizers:
164162
self.viewport_camera_controller = ViewportCameraController(self, self.cfg.viewer)
165163
else:
@@ -492,10 +490,7 @@ def render(self, recompute: bool = False) -> np.ndarray | None:
492490
return None
493491
elif self.render_mode == "rgb_array":
494492
# check that if any render could have happened
495-
has_visualizers = bool(self.sim.get_setting("/isaaclab/visualizer/types")) or bool(
496-
self.sim.get_setting("/isaaclab/video/auto_start_kit")
497-
)
498-
if not (self.sim.has_gui or self.sim.has_offscreen_render or has_visualizers):
493+
if not self.sim.can_render_rgb_array():
499494
raise RuntimeError(
500495
f"Cannot render '{self.render_mode}' - no GUI and offscreen rendering not enabled."
501496
" If running headless, make sure --enable_cameras is set."

source/isaaclab/isaaclab/envs/manager_based_env.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,7 @@ def _init_sim(self):
167167
# non-rendering modes.
168168
# Initialize when GUI is available OR when visualizers are active (headless rendering)
169169
# ViewerCfg camera updates are applied through renderer camera control.
170-
has_visualizers = bool(self.sim.get_setting("/isaaclab/visualizer/types")) or bool(
171-
self.sim.get_setting("/isaaclab/video/auto_start_kit")
172-
)
170+
has_visualizers = self.sim.has_active_visualizers()
173171
if self.sim.has_gui or has_visualizers:
174172
self.viewport_camera_controller = ViewportCameraController(self, self.cfg.viewer)
175173
else:

source/isaaclab/isaaclab/envs/manager_based_rl_env.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -275,10 +275,7 @@ def render(self, recompute: bool = False) -> np.ndarray | None:
275275
elif self.render_mode == "rgb_array":
276276
# check that if any render could have happened
277277
# Check for GUI, offscreen rendering, or visualizers
278-
has_visualizers = bool(self.sim.get_setting("/isaaclab/visualizer/types")) or bool(
279-
self.sim.get_setting("/isaaclab/video/auto_start_kit")
280-
)
281-
if not (self.sim.has_gui or self.sim.has_offscreen_render or has_visualizers):
278+
if not self.sim.can_render_rgb_array():
282279
raise RuntimeError(
283280
f"Cannot render '{self.render_mode}' - no GUI and offscreen rendering not enabled."
284281
" If running headless, make sure --enable_cameras is set."

source/isaaclab/isaaclab/sim/simulation_context.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,10 @@ def __init__(self, cfg: SimulationCfg | None = None):
190190

191191
# Monotonic physics-step counter used by camera sensors for
192192
self._physics_step_count: int = 0
193+
# Monotonic render-generation counter. This increments whenever render()
194+
# is executed and lets downstream camera freshness logic distinguish
195+
# render/reset transitions that occur without advancing physics steps.
196+
self._render_generation: int = 0
193197

194198
type(self)._instance = self # Mark as valid singleton only after successful init
195199

@@ -339,6 +343,16 @@ def has_offscreen_render(self) -> bool:
339343
"""Returns whether offscreen rendering is enabled (cached at init)."""
340344
return self._has_offscreen_render
341345

346+
def has_active_visualizers(self) -> bool:
347+
"""Return whether any visualizer path is active for rendering/camera control."""
348+
return bool(self.get_setting("/isaaclab/visualizer/types")) or bool(
349+
self.get_setting("/isaaclab/video/auto_start_kit")
350+
)
351+
352+
def can_render_rgb_array(self) -> bool:
353+
"""Return whether rgb-array rendering is currently available."""
354+
return self.has_gui or self.has_offscreen_render or self.has_active_visualizers()
355+
342356
@property
343357
def is_rendering(self) -> bool:
344358
"""Returns whether rendering is active (GUI, RTX sensors, visualizers, or XR)."""
@@ -354,6 +368,11 @@ def get_physics_dt(self) -> float:
354368
"""Returns the physics time step."""
355369
return self.physics_manager.get_physics_dt()
356370

371+
@property
372+
def render_generation(self) -> int:
373+
"""Returns a monotonic counter for render() executions."""
374+
return self._render_generation
375+
357376
def _create_default_visualizer_configs(self, requested_visualizers: list[str]) -> list:
358377
"""Create default visualizer configs for requested types.
359378
@@ -719,6 +738,7 @@ def render(self, mode: int | None = None) -> None:
719738
"""
720739
self.physics_manager.pre_render()
721740
self.update_visualizers(self.get_rendering_dt())
741+
self._render_generation += 1
722742

723743
# Call render callbacks
724744
if hasattr(self, "_render_callbacks"):

source/isaaclab_physx/isaaclab_physx/renderers/isaac_rtx_renderer_utils.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@
1414

1515
logger = logging.getLogger(__name__)
1616

17-
# Module-level dedup stamp: tracks the last (sim instance, physics step) at
17+
# Module-level dedup stamp: tracks the last (sim instance, physics step, render generation) at
1818
# which Kit's ``app.update()`` was pumped. Keyed on ``id(sim)`` so that a
1919
# new ``SimulationContext`` (e.g. in a new test) automatically invalidates
2020
# any stale stamp from a previous instance.
21-
_last_render_update_key: tuple[int, int] = (0, -1)
21+
_last_render_update_key: tuple[int, int, int] = (0, -1, -1)
2222

2323
# ---------------------------------------------------------------------------
2424
# RTX streaming status tracking
@@ -91,19 +91,19 @@ def _wait_for_streaming_complete() -> None:
9191

9292

9393
def ensure_isaac_rtx_render_update() -> None:
94-
"""Ensure the Isaac RTX renderer has been pumped for the current physics step.
94+
"""Ensure the Isaac RTX renderer has been pumped for the current sim step.
9595
9696
This keeps the Kit-specific ``app.update()`` logic inside the renderers
9797
package rather than in the backend-agnostic ``SimulationContext``.
9898
9999
Safe to call from multiple ``Camera`` / ``TiledCamera`` instances per step —
100100
only the first call triggers ``app.update()``. Subsequent calls are no-ops
101101
because the module-level ``_last_render_update_key`` already matches the
102-
current ``(id(sim), step_count)`` pair.
102+
current ``(id(sim), step_count, render_generation)`` tuple.
103103
104-
The key is a ``(sim_instance_id, step_count)`` tuple so that creating a new
105-
``SimulationContext`` (e.g. in a subsequent test) automatically invalidates
106-
any stale stamp left over from a previous instance.
104+
The key is a ``(sim_instance_id, step_count, render_generation)`` tuple so that:
105+
- creating a new ``SimulationContext`` invalidates stale stamps, and
106+
- render/reset transitions that do not advance physics step count still force a fresh update.
107107
108108
If RTX texture/geometry streaming is in progress, additional
109109
``app.update()`` calls are pumped until the streaming subsystem reports
@@ -120,7 +120,8 @@ def ensure_isaac_rtx_render_update() -> None:
120120
if sim is None:
121121
return
122122

123-
key = (id(sim), sim._physics_step_count)
123+
render_generation = getattr(sim, "render_generation", getattr(sim, "_render_generation", 0))
124+
key = (id(sim), sim._physics_step_count, render_generation)
124125
if _last_render_update_key == key:
125126
return # Already pumped this step (by another camera or a visualizer)
126127

0 commit comments

Comments
 (0)