Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Added
^^^^^

* Added :attr:`~isaaclab.sensors.camera.CameraCfg.background_color` to
:class:`~isaaclab.sensors.camera.CameraCfg` as a unified cross-backend way to set the camera
background to a solid color. Accepts normalized RGB floats ``(r, g, b)`` in ``[0, 1]``;
defaults to ``None`` (each backend's original default background).
11 changes: 11 additions & 0 deletions source/isaaclab/isaaclab/sensors/camera/camera_cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,17 @@ class OffsetCfg:
on :attr:`renderer_cfg` instead.
"""

background_color: tuple[float, float, float] | None = None
"""Background color for the camera as normalized RGB floats in ``[0, 1]``.

When set, the renderer fills pixels that miss all geometry with the given solid color.
When ``None`` (the default), each backend uses its own default background
(dome-light for RTX backends, gray for Newton).

The value is specified as ``(red, green, blue)`` with each component in ``[0, 1]``.
For example, ``(0.0, 0.0, 0.0)`` is black and ``(1.0, 1.0, 1.0)`` is white.
"""

renderer_cfg: RendererCfg = field(default_factory=RendererCfg)
"""Renderer configuration for camera sensor."""

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Added
^^^^^

* Added support for :attr:`~isaaclab.sensors.camera.CameraCfg.background_color` in
:class:`~isaaclab_newton.renderers.NewtonWarpRenderer`. When set, converts the normalized RGB
color to an ARGB clear color passed to ``SensorTiledCamera.ClearData`` on each render call.
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,16 @@ def __init__(self, newton_sensor: newton.sensors.SensorTiledCamera, spec: Camera
clipping_range = getattr(spawn, "clipping_range", None)
self.near_clip: float | None = float(clipping_range[0]) if clipping_range is not None else None
self.far_clip: float | None = float(clipping_range[1]) if clipping_range is not None else None

# ARGB clear color packed as uint32. Default is 93% gray (0xFFEEEEEE), matching the
# RTX renderer background and improving visibility of dark objects.
background_color = getattr(spec.cfg, "background_color", None)
if background_color is not None:
r, g, b = (max(0, min(255, round(c * 255))) for c in background_color)
self.clear_color: int = (0xFF << 24) | (r << 16) | (g << 8) | b
else:
self.clear_color = 0xFFEEEEEE

# Post-render PPISP pipeline composed when ``spec.cfg.isp_cfg`` is set.
# ``isp_cfg`` is already fully normalized by ``prepare_cameras`` by the time it reaches here.
self.ppisp_pipeline: PpispPipeline | None = None
Expand Down Expand Up @@ -471,9 +481,8 @@ def render(self, render_data: RenderData):
depth_image=render_data.outputs.depth_image,
normal_image=render_data.outputs.normals_image,
shape_index_image=render_data.outputs.instance_segmentation_image,
# ARGB 93% gray to improve visibility of dark objects and align with RTX renderer background
clear_data=newton.sensors.SensorTiledCamera.ClearData(
clear_color=0xFFEEEEEE,
clear_color=render_data.clear_color,
**({"clear_depth": render_data.far_clip} if _use_depth_clear else {}),
),
kernel_block_dim=self.cfg.kernel_block_dim,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Added
^^^^^

* Added support for :attr:`~isaaclab.sensors.camera.CameraCfg.background_color` in
:class:`~isaaclab_ov.renderers.OVRTXRenderer`. When set, authors
``omni:rtx:background:source:type = "color"`` and ``omni:rtx:background:source:color`` on the
USD render product instead of the default ``"domeLight"`` background.
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,7 @@ def _initialize_from_spec(self, spec: CameraRenderSpec):
data_types=data_types,
minimal_mode=_resolve_rtx_minimal_mode(data_types),
camera_rel_path=self._camera_rel_path,
background_color=getattr(spec.cfg, "background_color", None),
)
self._render_product_paths.append(render_product_path)

Expand Down
21 changes: 20 additions & 1 deletion source/isaaclab_ov/isaaclab_ov/renderers/ovrtx_usd.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ def build_render_scope_usd(
tiled_height: int,
minimal_mode: int | None = None,
render_var_configs: list[tuple[str, str, str]] | None = None,
background_color: tuple[float, float, float] | None = None,
) -> str:
"""Build the Render scope USD string (def Scope Render, RenderProduct, Vars).

Expand All @@ -118,6 +119,9 @@ def build_render_scope_usd(
tiled_height: Height of the tiled image.
minimal_mode: RTX minimal mode. None if not requested. Valid values are 1, 2, 3.
render_var_configs: Render variables to author. Uses the single render var arguments if not provided.
background_color: Solid background color as normalized RGB floats ``(r, g, b)`` in ``[0, 1]``.
When set, the render product uses ``"color"`` as the background source type.
When ``None``, the default ``"domeLight"`` background is used.

Returns:
The USD string for the render scope.
Expand All @@ -144,14 +148,24 @@ def build_render_scope_usd(
for _, name, source in render_var_configs
)

if background_color is not None:
r, g, b = background_color
background_lines = (
f'token omni:rtx:background:source:type = "color"\n'
f" float3 omni:rtx:background:source:color = ({r}, {g}, {b})"
Comment thread
mataylor-nvidia marked this conversation as resolved.
Outdated
)
else:
# Do not set background source type, so that the default dome light is used.
background_lines = 'token omni:rtx:background:source:type = "domeLight"'

return f'''
def Scope "Render"
{{
def RenderProduct "{render_product_name}" (
prepend apiSchemas = ["OmniRtxSettingsCommonAdvancedAPI_1"]
) {{
rel camera = [{camera_rel_list}]
token omni:rtx:background:source:type = "domeLight"
{background_lines}
float omni:rtx:rt:ambientLight:intensity = 1.0
{render_mode_block}
token[] omni:rtx:waitForEvents = ["AllLoadingFinished", "OnlyOnFirstRequest"]
Expand Down Expand Up @@ -181,6 +195,7 @@ def build_render_product_as_string(
data_types: list[str],
minimal_mode: int | None = None,
camera_rel_path: str = "Camera",
background_color: tuple[float, float, float] | None = None,
) -> tuple[str, str]:
"""Build the render product USD snippet as a string.

Expand All @@ -193,6 +208,9 @@ def build_render_product_as_string(
data_types: Data types from sensor config.
minimal_mode: RTX minimal mode. None if not requested. Valid values are 1, 2, 3.
camera_rel_path: Camera prim path relative to the env root (e.g. ``"Camera"`` or ``"Robot/head_cam"``).
background_color: Solid background color as normalized RGB floats ``(r, g, b)`` in ``[0, 1]``.
When set, the render product uses a solid color background instead of the dome light.
When ``None``, the default dome-light background is used.

Returns:
Tuple of (render product USD snippet as a string, absolute render product prim path).
Expand All @@ -217,6 +235,7 @@ def build_render_product_as_string(
tiled_height,
minimal_mode,
render_var_configs,
background_color,
)
return camera_content, render_product_path

Expand Down
32 changes: 32 additions & 0 deletions source/isaaclab_ov/test/test_ovrtx_usd.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,38 @@ def _assert_export_omits_env_children(exported: str, env_indices: range | list[i
assert f'def Xform "Object_env{env_idx}_only"' not in exported


def test_build_render_scope_usd_default_background_is_dome_light():
"""Default background (background_color=None) uses domeLight source type."""
render_scope = build_render_scope_usd(
camera_paths=["/World/envs/env_0/Camera"],
render_product_name="RenderProduct",
render_var_path="/Render/Vars/LdrColor",
render_var_name="LdrColor",
source_name="LdrColor",
tiled_width=16,
tiled_height=8,
)
assert 'token omni:rtx:background:source:type = "domeLight"' in render_scope
assert "omni:rtx:background:source:color" not in render_scope


def test_build_render_scope_usd_solid_background_color():
"""Providing background_color emits color source type and the color attribute."""
render_scope = build_render_scope_usd(
camera_paths=["/World/envs/env_0/Camera"],
render_product_name="RenderProduct",
render_var_path="/Render/Vars/LdrColor",
render_var_name="LdrColor",
source_name="LdrColor",
tiled_width=16,
tiled_height=8,
background_color=(1.0, 0.0, 0.5),
)
assert 'token omni:rtx:background:source:type = "color"' in render_scope
assert "float3 omni:rtx:background:source:color = (1.0, 0.0, 0.5)" in render_scope
assert 'token omni:rtx:background:source:type = "domeLight"' not in render_scope


def test_ovrtx_rgb_hdr_uses_hdr_color_render_var():
"""Requesting RGB_HDR from OVRTX selects the HdrColor render variable."""
assert get_render_var_config(["rgb_hdr"]) == ("/Render/Vars/HdrColor", "HdrColor", "HdrColor")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Added
^^^^^

* Added support for :attr:`~isaaclab.sensors.camera.CameraCfg.background_color` in
:class:`~isaaclab_physx.renderers.IsaacRtxRenderer`. When set, applies
``/rtx/background/source/type = 2`` (Color) and ``/rtx/background/source/color`` via the
settings manager during camera setup.
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,18 @@ def prepare_cameras(self, stage: Any, spec: CameraRenderSpec) -> None:
``exposure:*`` to neutral and applies ``OmniRtxCameraExposureAPI_1`` so
RTX's physical-camera exposure model does not compound on top of the
ISP. Without an ISP, the camera prim's authored exposure is left alone.

When :attr:`~isaaclab.sensors.camera.CameraCfg.background_color` is set,
applies the two RTX carb settings that switch the background to a solid color:
``/rtx/background/source/type = 2`` and ``/rtx/background/source/color``.
"""
background_color = getattr(spec.cfg, "background_color", None)
if background_color is not None:
settings = get_settings_manager()
r, g, b = background_color
settings.set("/rtx/background/source/type", 2)
settings.set("/rtx/background/source/color", (r, g, b))
Comment thread
mataylor-nvidia marked this conversation as resolved.
Outdated

if spec.cfg.isp_cfg is None:
return
try:
Expand Down
Loading