diff --git a/docs/source/overview/core-concepts/renderers.rst b/docs/source/overview/core-concepts/renderers.rst index 05730874b87..8854de40738 100644 --- a/docs/source/overview/core-concepts/renderers.rst +++ b/docs/source/overview/core-concepts/renderers.rst @@ -75,6 +75,13 @@ environments to remain spatially separated; overlapping partition bounds can mak content leak into another environment or disappear. Set the field to ``False`` to prioritize partition isolation and show only the selected environment in the Kit viewport. +The RTX spectator view requires Isaac Sim 6.1 or newer. On older releases the renderer +ignores ``rtx.scenePartitioning.showAllPartitionsByDefault``, and an unpartitioned +spectator camera matches no partition and renders an empty viewport. Isaac Lab therefore +skips scene-partition authoring altogether on those releases and logs a warning, leaving +every environment visible. Set ``show_all_partitions_by_default=False`` to keep partition +isolation there, with the Kit viewport bound to a single environment. + Prims outside the environment hierarchies remain in the shared background partition. Environment-owned ``PointInstancer`` markers can carry one matching scene-partition token per instance; markers without that ownership information remain shared. diff --git a/source/isaaclab_physx/changelog.d/mataylor-scene-partition-spectator-fallback.rst b/source/isaaclab_physx/changelog.d/mataylor-scene-partition-spectator-fallback.rst new file mode 100644 index 00000000000..ad270f76129 --- /dev/null +++ b/source/isaaclab_physx/changelog.d/mataylor-scene-partition-spectator-fallback.rst @@ -0,0 +1,11 @@ +Fixed +^^^^^ + +* Fixed an empty Kit viewport when per-environment scene partitioning ran on an Isaac Sim + release whose RTX renderer does not implement the all-partitions spectator view + (``/rtx/scenePartitioning/showAllPartitionsByDefault``, added in Isaac Sim 6.1). Interactive + viewport cameras inherit no ``omni:scenePartition`` token, so on those runtimes they matched + no partition and rendered nothing. :meth:`~isaaclab_physx.renderers.IsaacRtxRenderer.prepare_stage` + now leaves the stage unpartitioned when the spectator view is requested but unsupported. Set + ``IsaacRtxRendererCfg.global_settings.show_all_partitions_by_default`` to ``False`` to keep + per-environment isolation on those runtimes; the viewport is then bound to a single environment. diff --git a/source/isaaclab_physx/isaaclab_physx/renderers/isaac_rtx_renderer.py b/source/isaaclab_physx/isaaclab_physx/renderers/isaac_rtx_renderer.py index 6aa8066b0ce..49ade5de40d 100644 --- a/source/isaaclab_physx/isaaclab_physx/renderers/isaac_rtx_renderer.py +++ b/source/isaaclab_physx/isaaclab_physx/renderers/isaac_rtx_renderer.py @@ -29,10 +29,12 @@ from isaaclab.utils.warp.warp_math import clamp_depth_to_inf_wp, replace_inf_depth_wp from .isaac_rtx_renderer_utils import ( + SHOW_ALL_PARTITIONS_MIN_ISAAC_SIM_VERSION, apply_isaac_rtx_determinism_settings, apply_isaac_rtx_global_settings, ensure_isaac_rtx_render_update, ensure_rtx_hydra_engine_attached, + show_all_partitions_supported, ) logger = logging.getLogger(__name__) @@ -205,11 +207,32 @@ def prepare_stage(self, stage: Usd.Stage, num_envs: int) -> None: non-primvar ``omni:scenePartition`` token on every :class:`UsdGeom.Camera` descendant. RTX honors primvar inheritance, so the env-root primvar propagates to all descendant geometry and isolates each env's render tile. + + Authoring is also skipped when the all-partitions spectator view is requested but the + running RTX renderer does not implement it, because partitioning every env root would + then leave interactive viewports with nothing to render. See :meth:`~isaaclab.renderers.base_renderer.BaseRenderer.prepare_stage`.""" if not self.cfg.enable_scene_partitioning: return + # Kit viewport cameras live outside ``/World/envs``, so they inherit no partition token and + # depend on the spectator view to see partitioned geometry. On a renderer that ignores the + # spectator setting such a camera matches no partition and the viewport renders black, so + # leave the stage unpartitioned rather than half-applying the feature. Setting + # ``show_all_partitions_by_default=False`` keeps partitioning on these runtimes; the + # visualizer then binds the viewport to a single environment. + if self.cfg.global_settings.show_all_partitions_by_default and not show_all_partitions_supported(): + logger.warning( + "Skipping RTX scene partitioning: the all-partitions spectator view requires Isaac Sim %s or" + " newer, but %s is running. Partitioning without it renders an empty Kit viewport. Set" + " IsaacRtxRendererCfg.global_settings.show_all_partitions_by_default=False to partition anyway" + " and view a single environment, or upgrade Isaac Sim.", + SHOW_ALL_PARTITIONS_MIN_ISAAC_SIM_VERSION, + get_isaac_sim_version(), + ) + return + logger.debug( "Per-environment RTX scene partitioning is enabled. Authoring primvars:omni:scenePartition on %d env(s).", num_envs, diff --git a/source/isaaclab_physx/isaaclab_physx/renderers/isaac_rtx_renderer_utils.py b/source/isaaclab_physx/isaaclab_physx/renderers/isaac_rtx_renderer_utils.py index ae09028ac23..4e8980fcb1d 100644 --- a/source/isaaclab_physx/isaaclab_physx/renderers/isaac_rtx_renderer_utils.py +++ b/source/isaaclab_physx/isaaclab_physx/renderers/isaac_rtx_renderer_utils.py @@ -11,15 +11,34 @@ import time from typing import Any +from packaging.version import Version + import omni.usd import isaaclab.sim as sim_utils from isaaclab.app.settings_manager import SettingsManager, get_settings_manager +from isaaclab.utils.version import get_isaac_sim_version from .isaac_rtx_renderer_cfg import IsaacRtxRendererGlobalSettingsCfg logger = logging.getLogger(__name__) +SHOW_ALL_PARTITIONS_MIN_ISAAC_SIM_VERSION = Version("6.1") +"""First Isaac Sim release whose RTX renderer implements the all-partitions spectator view.""" + + +def show_all_partitions_supported() -> bool: + """Return whether the running RTX renderer implements the all-partitions spectator view. + + ``/rtx/scenePartitioning/showAllPartitionsByDefault`` makes a camera that carries no + ``omni:scenePartition`` token render every partition. Carb settings are schemaless, so the + experience files set the key on every runtime and reading it back cannot distinguish a + renderer that honors it from one that ignores it. Older renderers cull such a camera down to + nothing, so the capability is resolved from the Isaac Sim version instead. + """ + return get_isaac_sim_version() >= SHOW_ALL_PARTITIONS_MIN_ISAAC_SIM_VERSION + + _RTX_FIELD_TO_SETTING = { "enable_translucency": "/rtx/translucency/enabled", "enable_reflections": "/rtx/reflections/enabled", diff --git a/source/isaaclab_physx/test/renderers/test_isaac_rtx_renderer_scene_partitioning.py b/source/isaaclab_physx/test/renderers/test_isaac_rtx_renderer_scene_partitioning.py index 0c25ee6b31e..9b7a60f37d7 100644 --- a/source/isaaclab_physx/test/renderers/test_isaac_rtx_renderer_scene_partitioning.py +++ b/source/isaaclab_physx/test/renderers/test_isaac_rtx_renderer_scene_partitioning.py @@ -33,6 +33,7 @@ import os +import isaaclab_physx.renderers.isaac_rtx_renderer as isaac_rtx_renderer_module import pytest import torch import warp as wp @@ -57,17 +58,28 @@ def _isolation_renderer_cfg() -> IsaacRtxRendererCfg: return IsaacRtxRendererCfg(global_settings=IsaacRtxRendererGlobalSettingsCfg(show_all_partitions_by_default=False)) +def _stage_with_one_env(): + """Build an in-memory stage holding a single environment root.""" + from pxr import Usd + + stage = Usd.Stage.CreateInMemory() + stage.DefinePrim("/World", "Xform") + stage.DefinePrim("/World/envs/env_0", "Xform") + return stage + + +def _force_spectator_support(monkeypatch: pytest.MonkeyPatch, supported: bool) -> None: + """Pin the RTX spectator-view capability so authoring does not depend on the running Isaac Sim.""" + monkeypatch.setattr(isaac_rtx_renderer_module, "show_all_partitions_supported", lambda: supported) + + @pytest.mark.isaacsim_ci def test_partitioning_enabled_by_default(monkeypatch): """``primvars:omni:scenePartition`` must be authored when the environment variable is absent.""" - from pxr import Usd - monkeypatch.delenv(_ENV_VAR, raising=False) + _force_spectator_support(monkeypatch, True) - stage = Usd.Stage.CreateInMemory() - world = stage.DefinePrim("/World", "Xform") # noqa: F841 - env0 = stage.DefinePrim("/World/envs/env_0", "Xform") # noqa: F841 - + stage = _stage_with_one_env() renderer = object.__new__(IsaacRtxRenderer) renderer.cfg = IsaacRtxRendererCfg() renderer.prepare_stage(stage, num_envs=1) @@ -82,14 +94,10 @@ def test_partitioning_enabled_by_default(monkeypatch): @pytest.mark.parametrize(("cfg_enabled", "environment_value"), [(True, "0"), (False, "1")]) def test_partitioning_cfg_overrides_legacy_environment_variable(monkeypatch, cfg_enabled: bool, environment_value: str): """The renderer configuration should take precedence over the legacy environment variable.""" - from pxr import Usd - monkeypatch.setenv(_ENV_VAR, environment_value) + _force_spectator_support(monkeypatch, True) - stage = Usd.Stage.CreateInMemory() - world = stage.DefinePrim("/World", "Xform") # noqa: F841 - env0 = stage.DefinePrim("/World/envs/env_0", "Xform") # noqa: F841 - + stage = _stage_with_one_env() renderer = object.__new__(IsaacRtxRenderer) renderer.cfg = IsaacRtxRendererCfg(enable_scene_partitioning=cfg_enabled) renderer.prepare_stage(stage, num_envs=1) @@ -98,6 +106,42 @@ def test_partitioning_cfg_overrides_legacy_environment_variable(monkeypatch, cfg assert prim.HasAttribute("primvars:omni:scenePartition") is cfg_enabled +@pytest.mark.isaacsim_ci +def test_partitioning_skipped_when_spectator_view_unsupported(monkeypatch: pytest.MonkeyPatch): + """A renderer that ignores the spectator setting must be left unpartitioned. + + Partitioning every env root on such a runtime culls the Kit viewport camera -- which carries no + ``omni:scenePartition`` token -- down to an empty image. + """ + monkeypatch.delenv(_ENV_VAR, raising=False) + _force_spectator_support(monkeypatch, False) + + stage = _stage_with_one_env() + renderer = object.__new__(IsaacRtxRenderer) + renderer.cfg = IsaacRtxRendererCfg() + renderer.prepare_stage(stage, num_envs=1) + + prim = stage.GetPrimAtPath("/World/envs/env_0") + assert not prim.HasAttribute("primvars:omni:scenePartition"), ( + "Partitioning must be skipped when the spectator view is requested but unsupported." + ) + + +@pytest.mark.isaacsim_ci +def test_partitioning_kept_without_spectator_view_on_unsupported_runtime(monkeypatch: pytest.MonkeyPatch): + """Opting out of the spectator view keeps per-env isolation on renderers that lack it.""" + monkeypatch.delenv(_ENV_VAR, raising=False) + _force_spectator_support(monkeypatch, False) + + stage = _stage_with_one_env() + renderer = object.__new__(IsaacRtxRenderer) + renderer.cfg = _isolation_renderer_cfg() + renderer.prepare_stage(stage, num_envs=1) + + prim = stage.GetPrimAtPath("/World/envs/env_0") + assert prim.GetAttribute("primvars:omni:scenePartition").Get() == "env_0" + + @pytest.mark.isaacsim_ci def test_partitioning_isolates_rigid_object(monkeypatch: pytest.MonkeyPatch): """Per-env :class:`~isaaclab.assets.RigidObject` instances at unique world positions render