Skip to content
Merged
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 CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ Guidelines for modifications:
* Dhyan Thakkar
* Dongxuan Fan
* Dorsa Rohani
* Ege Sekkin
* Emily Sturman
* Emmanuel Ferdman
* Fabian Jenelten
Expand Down
13 changes: 5 additions & 8 deletions docs/source/how-to/save_camera_output.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ directory.
Saving using Replicator Basic Writer
------------------------------------

.. note::
The BasicWriter is part of the Omniverse Replicator ecosystem and is specific to the default
Isaac RTX renderer backend. Other renderer backends may require different save workflows.

To save camera outputs, we use the basic write class from Omniverse Replicator. This class allows us to save the
images in a numpy format. For more information on the basic writer, please check the
`documentation <https://docs.omniverse.nvidia.com/extensions/latest/ext_replicator/writer_examples.html>`_.
Expand All @@ -32,18 +36,11 @@ images in a numpy format. For more information on the basic writer, please check

While stepping the simulator, the images can be saved to the defined folder. Since the BasicWriter only supports
saving data using NumPy format, we first need to convert the PyTorch sensors to NumPy arrays before packing
them in a dictionary.
them in a dictionary and writing with the BasicWriter.
Comment thread
nvsekkin marked this conversation as resolved.

.. literalinclude:: ../../../scripts/tutorials/04_sensors/run_usd_camera.py
:language: python
:start-at: # Save images from camera at camera_index
:end-at: single_cam_info = camera.data.info[camera_index]

After this step, we can save the images using the BasicWriter.

.. literalinclude:: ../../../scripts/tutorials/04_sensors/run_usd_camera.py
:language: python
:start-at: # Pack data back into replicator format to save them using its writer
:end-at: rep_writer.write(rep_output)


Expand Down
6 changes: 2 additions & 4 deletions scripts/tutorials/04_sensors/run_ray_caster_camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,10 @@ def run_simulator(sim: sim_utils.SimulationContext, scene_entities: dict):
single_cam_data = convert_dict_to_backend(
{k: v[camera_index] for k, v in camera.data.output.items()}, backend="numpy"
)
# Extract the other information
single_cam_info = camera.data.info[camera_index]

# Pack data back into replicator format to save them using its writer
rep_output = {"annotators": {}}
for key, data, info in zip(single_cam_data.keys(), single_cam_data.values(), single_cam_info.values()):
for key, data in single_cam_data.items():
info = camera.data.info.get(key)
if info is not None:
rep_output["annotators"][key] = {"render_product": {"data": data, **info}}
else:
Expand Down
6 changes: 2 additions & 4 deletions scripts/tutorials/04_sensors/run_usd_camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,12 +232,10 @@ def run_simulator(sim: sim_utils.SimulationContext, scene_entities: dict):
{k: v[camera_index] for k, v in camera.data.output.items()}, backend="numpy"
)

# Extract the other information
single_cam_info = camera.data.info[camera_index]

# Pack data back into replicator format to save them using its writer
rep_output = {"annotators": {}}
for key, data, info in zip(single_cam_data.keys(), single_cam_data.values(), single_cam_info.values()):
for key, data in single_cam_data.items():
info = camera.data.info.get(key)
if info is not None:
rep_output["annotators"][key] = {"render_product": {"data": data, **info}}
else:
Expand Down
2 changes: 1 addition & 1 deletion source/isaaclab/config/extension.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]

# Note: Semantic Versioning is used: https://semver.org/
version = "4.5.33"
version = "4.6.0"

# Description
title = "Isaac Lab framework for Robot Learning"
Expand Down
39 changes: 39 additions & 0 deletions source/isaaclab/docs/CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,45 @@
Changelog
---------

4.6.0 (2026-04-13)
~~~~~~~~~~~~~~~~~~

Changed
^^^^^^^

* Unified :class:`~isaaclab.sensors.camera.Camera` and :class:`~isaaclab.sensors.camera.TiledCamera`
into a single implementation. :class:`Camera` now delegates all rendering to the
:class:`~isaaclab.renderers.Renderer` abstraction (same approach :class:`TiledCamera` used).
The public API is unchanged for :class:`Camera` users.
* **Breaking:** :attr:`~isaaclab.sensors.camera.CameraData.info` is now a flat
``dict[str, Any]`` keyed by data type (e.g. ``camera.data.info["semantic_segmentation"]``).
The metadata is shared across all cameras and identical to what the underlying renderer returns.

- **Camera users (old):** replace ``camera.data.info[cam_idx][data_type]`` with
``camera.data.info[data_type]``.
- **TiledCamera users (old):** access pattern ``camera.data.info[data_type]`` is unchanged.

* **Breaking:** :meth:`~isaaclab.renderers.BaseRenderer.write_output` has been replaced by
:meth:`~isaaclab.renderers.BaseRenderer.read_output`. The new method receives the full
:class:`~isaaclab.sensors.camera.CameraData` instance and iterates output types internally.
Custom renderer implementations must replace ``write_output(render_data, output_name, output_data)``
with ``read_output(render_data, camera_data)``.

Deprecated
^^^^^^^^^^

* :class:`~isaaclab.sensors.camera.TiledCamera` is deprecated. Use
:class:`~isaaclab.sensors.camera.Camera` directly — it now supports all renderer backends.
* :class:`~isaaclab.sensors.camera.TiledCameraCfg` is deprecated. Use
:class:`~isaaclab.sensors.camera.CameraCfg` directly.

Removed
^^^^^^^

* Removed :attr:`~isaaclab.sensors.camera.Camera.render_product_paths`. Render products are
now managed internally by the renderer backend and are not part of the public API.


4.5.33 (2026-04-13)
~~~~~~~~~~~~~~~~~~~

Expand Down
9 changes: 5 additions & 4 deletions source/isaaclab/isaaclab/renderers/base_renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import torch

from isaaclab.sensors import SensorBase
from isaaclab.sensors.camera.camera_data import CameraData


class BaseRenderer(ABC):
Expand Down Expand Up @@ -93,13 +94,13 @@ def render(self, render_data: Any) -> None:
pass

@abstractmethod
def write_output(self, render_data: Any, output_name: str, output_data: torch.Tensor) -> None:
"""Write a specific output type to the given buffer.
def read_output(self, render_data: Any, camera_data: CameraData) -> None:
"""Read rendered outputs from the renderer into the camera data container.

Args:
render_data: The render data object from :meth:`create_render_data`.
output_name: Name of the output (e.g. ``"rgba"``, ``"depth"``).
output_data: Pre-allocated tensor to write the output into.
camera_data: The :class:`~isaaclab.sensors.camera.camera_data.CameraData`
Comment thread
nvsekkin marked this conversation as resolved.
instance to populate.
"""
pass

Expand Down
Loading
Loading