Skip to content

Commit 2a17d48

Browse files
Add background_color to CameraCfg for cross-backend solid color backgrounds
Adds a new optional `background_color` attribute to `CameraCfg` that accepts normalized RGB floats and wires through to all three renderer backends: - Newton: converts to ARGB uint32 and passes as `SensorTiledCamera.ClearData.clear_color` - OV RTX: authors `omni:rtx:background:source:type = "color"` and the corresponding color attribute on the USD render product - PhysX RTX (IsaacRtx): applies `/rtx/background/source/type = 2` and color via the settings manager Defaults to `None` so existing behavior is preserved for all backends.
1 parent 03904ab commit 2a17d48

10 files changed

Lines changed: 113 additions & 3 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Added
2+
^^^^^
3+
4+
* Added :attr:`~isaaclab.sensors.camera.CameraCfg.background_color` to
5+
:class:`~isaaclab.sensors.camera.CameraCfg` as a unified cross-backend way to set the camera
6+
background to a solid color. Accepts normalized RGB floats ``(r, g, b)`` in ``[0, 1]``;
7+
defaults to ``None`` (each backend's original default background).

source/isaaclab/isaaclab/sensors/camera/camera_cfg.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,17 @@ class OffsetCfg:
190190
on :attr:`renderer_cfg` instead.
191191
"""
192192

193+
background_color: tuple[float, float, float] | None = None
194+
"""Background color for the camera as normalized RGB floats in ``[0, 1]``.
195+
196+
When set, the renderer fills pixels that miss all geometry with the given solid color.
197+
When ``None`` (the default), each backend uses its own default background
198+
(dome-light for RTX backends, gray for Newton).
199+
200+
The value is specified as ``(red, green, blue)`` with each component in ``[0, 1]``.
201+
For example, ``(0.0, 0.0, 0.0)`` is black and ``(1.0, 1.0, 1.0)`` is white.
202+
"""
203+
193204
renderer_cfg: RendererCfg = field(default_factory=RendererCfg)
194205
"""Renderer configuration for camera sensor."""
195206

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Added
2+
^^^^^
3+
4+
* Added support for :attr:`~isaaclab.sensors.camera.CameraCfg.background_color` in
5+
:class:`~isaaclab_newton.renderers.NewtonWarpRenderer`. When set, converts the normalized RGB
6+
color to an ARGB clear color passed to ``SensorTiledCamera.ClearData`` on each render call.

source/isaaclab_newton/isaaclab_newton/renderers/newton_warp_renderer.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,16 @@ def __init__(self, newton_sensor: newton.sensors.SensorTiledCamera, spec: Camera
112112
clipping_range = getattr(spawn, "clipping_range", None)
113113
self.near_clip: float | None = float(clipping_range[0]) if clipping_range is not None else None
114114
self.far_clip: float | None = float(clipping_range[1]) if clipping_range is not None else None
115+
116+
# ARGB clear color packed as uint32. Default is 93% gray (0xFFEEEEEE), matching the
117+
# RTX renderer background and improving visibility of dark objects.
118+
background_color = getattr(spec.cfg, "background_color", None)
119+
if background_color is not None:
120+
r, g, b = (max(0, min(255, round(c * 255))) for c in background_color)
121+
self.clear_color: int = (0xFF << 24) | (r << 16) | (g << 8) | b
122+
else:
123+
self.clear_color = 0xFFEEEEEE
124+
115125
# Post-render PPISP pipeline composed when ``spec.cfg.isp_cfg`` is set.
116126
# ``isp_cfg`` is already fully normalized by ``prepare_cameras`` by the time it reaches here.
117127
self.ppisp_pipeline: PpispPipeline | None = None
@@ -471,9 +481,8 @@ def render(self, render_data: RenderData):
471481
depth_image=render_data.outputs.depth_image,
472482
normal_image=render_data.outputs.normals_image,
473483
shape_index_image=render_data.outputs.instance_segmentation_image,
474-
# ARGB 93% gray to improve visibility of dark objects and align with RTX renderer background
475484
clear_data=newton.sensors.SensorTiledCamera.ClearData(
476-
clear_color=0xFFEEEEEE,
485+
clear_color=render_data.clear_color,
477486
**({"clear_depth": render_data.far_clip} if _use_depth_clear else {}),
478487
),
479488
kernel_block_dim=self.cfg.kernel_block_dim,
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Added
2+
^^^^^
3+
4+
* Added support for :attr:`~isaaclab.sensors.camera.CameraCfg.background_color` in
5+
:class:`~isaaclab_ov.renderers.OVRTXRenderer`. When set, authors
6+
``omni:rtx:background:source:type = "color"`` and ``omni:rtx:background:source:color`` on the
7+
USD render product instead of the default ``"domeLight"`` background.

source/isaaclab_ov/isaaclab_ov/renderers/ovrtx_renderer.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,7 @@ def _initialize_from_spec(self, spec: CameraRenderSpec):
405405
data_types=data_types,
406406
minimal_mode=_resolve_rtx_minimal_mode(data_types),
407407
camera_rel_path=self._camera_rel_path,
408+
background_color=getattr(spec.cfg, "background_color", None),
408409
)
409410
self._render_product_paths.append(render_product_path)
410411

source/isaaclab_ov/isaaclab_ov/renderers/ovrtx_usd.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ def build_render_scope_usd(
105105
tiled_height: int,
106106
minimal_mode: int | None = None,
107107
render_var_configs: list[tuple[str, str, str]] | None = None,
108+
background_color: tuple[float, float, float] | None = None,
108109
) -> str:
109110
"""Build the Render scope USD string (def Scope Render, RenderProduct, Vars).
110111
@@ -118,6 +119,9 @@ def build_render_scope_usd(
118119
tiled_height: Height of the tiled image.
119120
minimal_mode: RTX minimal mode. None if not requested. Valid values are 1, 2, 3.
120121
render_var_configs: Render variables to author. Uses the single render var arguments if not provided.
122+
background_color: Solid background color as normalized RGB floats ``(r, g, b)`` in ``[0, 1]``.
123+
When set, the render product uses ``"color"`` as the background source type.
124+
When ``None``, the default ``"domeLight"`` background is used.
121125
122126
Returns:
123127
The USD string for the render scope.
@@ -144,14 +148,24 @@ def build_render_scope_usd(
144148
for _, name, source in render_var_configs
145149
)
146150

151+
if background_color is not None:
152+
r, g, b = background_color
153+
background_lines = (
154+
f'token omni:rtx:background:source:type = "color"\n'
155+
f" float3 omni:rtx:background:source:color = ({r}, {g}, {b})"
156+
)
157+
else:
158+
# Do not set background source type
159+
background_lines = ""
160+
147161
return f'''
148162
def Scope "Render"
149163
{{
150164
def RenderProduct "{render_product_name}" (
151165
prepend apiSchemas = ["OmniRtxSettingsCommonAdvancedAPI_1"]
152166
) {{
153167
rel camera = [{camera_rel_list}]
154-
token omni:rtx:background:source:type = "domeLight"
168+
{background_lines}
155169
float omni:rtx:rt:ambientLight:intensity = 1.0
156170
{render_mode_block}
157171
token[] omni:rtx:waitForEvents = ["AllLoadingFinished", "OnlyOnFirstRequest"]
@@ -181,6 +195,7 @@ def build_render_product_as_string(
181195
data_types: list[str],
182196
minimal_mode: int | None = None,
183197
camera_rel_path: str = "Camera",
198+
background_color: tuple[float, float, float] | None = None,
184199
) -> tuple[str, str]:
185200
"""Build the render product USD snippet as a string.
186201
@@ -193,6 +208,9 @@ def build_render_product_as_string(
193208
data_types: Data types from sensor config.
194209
minimal_mode: RTX minimal mode. None if not requested. Valid values are 1, 2, 3.
195210
camera_rel_path: Camera prim path relative to the env root (e.g. ``"Camera"`` or ``"Robot/head_cam"``).
211+
background_color: Solid background color as normalized RGB floats ``(r, g, b)`` in ``[0, 1]``.
212+
When set, the render product uses a solid color background instead of the dome light.
213+
When ``None``, the default dome-light background is used.
196214
197215
Returns:
198216
Tuple of (render product USD snippet as a string, absolute render product prim path).
@@ -217,6 +235,7 @@ def build_render_product_as_string(
217235
tiled_height,
218236
minimal_mode,
219237
render_var_configs,
238+
background_color,
220239
)
221240
return camera_content, render_product_path
222241

source/isaaclab_ov/test/test_ovrtx_usd.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,38 @@ def _assert_export_omits_env_children(exported: str, env_indices: range | list[i
7676
assert f'def Xform "Object_env{env_idx}_only"' not in exported
7777

7878

79+
def test_build_render_scope_usd_default_background_is_dome_light():
80+
"""Default background (background_color=None) uses domeLight source type."""
81+
render_scope = build_render_scope_usd(
82+
camera_paths=["/World/envs/env_0/Camera"],
83+
render_product_name="RenderProduct",
84+
render_var_path="/Render/Vars/LdrColor",
85+
render_var_name="LdrColor",
86+
source_name="LdrColor",
87+
tiled_width=16,
88+
tiled_height=8,
89+
)
90+
assert 'token omni:rtx:background:source:type = "domeLight"' in render_scope
91+
assert "omni:rtx:background:source:color" not in render_scope
92+
93+
94+
def test_build_render_scope_usd_solid_background_color():
95+
"""Providing background_color emits color source type and the color attribute."""
96+
render_scope = build_render_scope_usd(
97+
camera_paths=["/World/envs/env_0/Camera"],
98+
render_product_name="RenderProduct",
99+
render_var_path="/Render/Vars/LdrColor",
100+
render_var_name="LdrColor",
101+
source_name="LdrColor",
102+
tiled_width=16,
103+
tiled_height=8,
104+
background_color=(1.0, 0.0, 0.5),
105+
)
106+
assert 'token omni:rtx:background:source:type = "color"' in render_scope
107+
assert "float3 omni:rtx:background:source:color = (1.0, 0.0, 0.5)" in render_scope
108+
assert 'token omni:rtx:background:source:type = "domeLight"' not in render_scope
109+
110+
79111
def test_ovrtx_rgb_hdr_uses_hdr_color_render_var():
80112
"""Requesting RGB_HDR from OVRTX selects the HdrColor render variable."""
81113
assert get_render_var_config(["rgb_hdr"]) == ("/Render/Vars/HdrColor", "HdrColor", "HdrColor")
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Added
2+
^^^^^
3+
4+
* Added support for :attr:`~isaaclab.sensors.camera.CameraCfg.background_color` in
5+
:class:`~isaaclab_physx.renderers.IsaacRtxRenderer`. When set, applies
6+
``/rtx/background/source/type = 2`` (Color) and ``/rtx/background/source/color`` via the
7+
settings manager during camera setup.

source/isaaclab_physx/isaaclab_physx/renderers/isaac_rtx_renderer.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,18 @@ def prepare_cameras(self, stage: Any, spec: CameraRenderSpec) -> None:
142142
``exposure:*`` to neutral and applies ``OmniRtxCameraExposureAPI_1`` so
143143
RTX's physical-camera exposure model does not compound on top of the
144144
ISP. Without an ISP, the camera prim's authored exposure is left alone.
145+
146+
When :attr:`~isaaclab.sensors.camera.CameraCfg.background_color` is set,
147+
applies the two RTX carb settings that switch the background to a solid color:
148+
``/rtx/background/source/type = 2`` and ``/rtx/background/source/color``.
145149
"""
150+
background_color = getattr(spec.cfg, "background_color", None)
151+
if background_color is not None:
152+
settings = get_settings_manager()
153+
r, g, b = background_color
154+
settings.set("/rtx/background/source/type", 2)
155+
settings.set("/rtx/background/source/color", (r, g, b))
156+
146157
if spec.cfg.isp_cfg is None:
147158
return
148159
try:

0 commit comments

Comments
 (0)