Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
0b7b9be
Move sensor documentation to Concepts
AntoineRichard Aug 26, 2026
5401db1
Fix sensor documentation review findings
AntoineRichard Aug 26, 2026
b5fb170
Clarify contact sensor backend behavior
AntoineRichard Aug 26, 2026
9ca4e15
Add renderer output gallery
AntoineRichard Aug 27, 2026
f6699da
Format renderer gallery capture tools
AntoineRichard Aug 27, 2026
e1fc6b4
Make renderer gallery meshes texture-ready
AntoineRichard Aug 27, 2026
fa63de2
Expand renderer gallery scene
AntoineRichard Aug 27, 2026
199fda1
Keep renderer capture tools out of PR
AntoineRichard Aug 27, 2026
8be6b37
Restore media README from PR base
AntoineRichard Aug 27, 2026
70cc51b
Regenerate Isaac RTX gallery with synchronized motion
AntoineRichard Aug 27, 2026
7ff066e
Match renderer gallery lighting and motion
AntoineRichard Aug 27, 2026
d6501d9
Correct renderer gallery media and guidance
AntoineRichard Aug 27, 2026
4c9bc5f
Unify gallery semantics and remove legacy media
AntoineRichard Aug 27, 2026
096e612
Clarify camera examples and keep capture stage local
AntoineRichard Aug 27, 2026
9f75d98
Clarify renderer modes and examples
AntoineRichard Aug 28, 2026
3e2aafe
Refine renderer comparisons
AntoineRichard Aug 28, 2026
9b14879
Wrap renderer preset captions
AntoineRichard Aug 28, 2026
0fcc479
Clarify renderer output examples
AntoineRichard Aug 28, 2026
7b91013
Move renderer and Ray Caster concepts
AntoineRichard Aug 28, 2026
65460b3
Correct sensor contracts and remove redirects
AntoineRichard Sep 1, 2026
f86cbd3
Clarify renderer roles and capabilities
AntoineRichard Sep 1, 2026
a3157ef
Regenerate renderer gallery review images
AntoineRichard Sep 1, 2026
60b7cb9
Add renderer gallery tooling
AntoineRichard Sep 1, 2026
01ff1d8
Merge develop into sensor documentation
AntoineRichard Sep 5, 2026
280d17c
Use frame depth bounds in renderer gallery
AntoineRichard Sep 5, 2026
db45d2f
Add collapsible renderer details
AntoineRichard Sep 5, 2026
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 docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ Table of Contents

source/concepts/backends_and_presets
source/concepts/actuators
source/concepts/sensors/index


.. toctree::
Expand Down

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awesome!

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
316 changes: 316 additions & 0 deletions docs/source/concepts/sensors/camera.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,316 @@
.. _concepts_sensors_camera:
.. _overview_sensors_camera:

.. currentmodule:: isaaclab

Camera
======

A :class:`~sensors.Camera` defines what to capture: camera pose, projection, resolution, sampling
period, and output data types. A renderer defines how those images are produced. Keeping these
responsibilities separate lets one camera configuration work with different physics and rendering
backends.

Camera data is expensive compared with low-dimensional state. Isaac Lab therefore batches the
camera copies from cloned environments into tiled render passes and exposes the de-tiled result as
one device-resident buffer per requested output.

Rendering model
---------------

:attr:`~sensors.CameraCfg.renderer_cfg` selects the renderer. A plain
:class:`~isaaclab.renderers.RendererCfg` requests the runtime default. Use a concrete configuration
when the renderer must be fixed:

.. list-table::
:header-rows: 1
:widths: 34 23 43

* - Renderer configuration
- Requires Isaac Sim
- Characteristics
* - :class:`~isaaclab_physx.renderers.IsaacRtxRendererCfg`
- Yes
- Replicator and RTX rendering through Isaac Sim
* - :class:`~isaaclab_ov.renderers.OVRTXRendererCfg`
- No
- Kit-less RTX rendering through ``isaaclab_ov``
* - :class:`~isaaclab_newton.renderers.NewtonWarpRendererCfg`
- No
- Kit-less Warp rasterization through Newton

For an environment that exposes renderer presets, select the renderer at launch instead of editing
the scene configuration:

.. code-block:: bash

uv run isaaclab train --rl_library rsl_rl \
--task Isaac-Cartpole-Camera-Direct renderer=newton_renderer

See :doc:`/source/concepts/backends_and_presets` for preset discovery and
:ref:`renderer-visual-comparison` for a same-scene comparison of the renderer outputs.

Configure a camera
------------------

A camera can spawn a pinhole or fisheye camera prim, or bind to a camera already on the stage.
``offset`` uses the convention declared on :class:`~sensors.CameraCfg.OffsetCfg`:

* ``world``: forward ``+X``, up ``+Z``.
* ``ros``: forward ``+Z``, up ``-Y``.
* ``opengl``: forward ``-Z``, up ``+Y``.

.. code-block:: python

import isaaclab.sim as sim_utils
from isaaclab.sensors import CameraCfg
from isaaclab_newton.renderers import NewtonWarpRendererCfg

front_camera = CameraCfg(
prim_path="{ENV_REGEX_NS}/Robot/base/front_camera",
update_period=0.05,
height=240,
width=320,
data_types=["rgb", "depth", "normals"],
spawn=sim_utils.PinholeCameraCfg(
focal_length=24.0,
horizontal_aperture=20.955,
clipping_range=(0.1, 20.0),
),
offset=CameraCfg.OffsetCfg(
pos=(0.45, 0.0, 0.1),
rot=(0.0, 0.0, 0.0, 1.0),
convention="world",
),
renderer_cfg=NewtonWarpRendererCfg(),
)

A renderer instance is reused only when cameras use equal renderer configurations of the same
concrete configuration type. Different renderer settings create distinct instances. Camera
configurations, including output types and backgrounds, remain per sensor.

Read camera data
----------------

:attr:`~sensors.CameraData.output` maps each requested name to a
:class:`~isaaclab.utils.warp.ProxyArray`. For ``N`` camera views, height ``H``, width ``W``, and
``C`` channels, each output has shape ``(N, H, W, C)``. Use ``torch`` for a cached zero-copy Torch
view or ``warp`` for the underlying Warp array:

.. code-block:: python

camera_data = scene["front_camera"].data
rgb = camera_data.output["rgb"].torch
depth = camera_data.output["depth"].torch
intrinsics = camera_data.intrinsic_matrices.torch

Camera pose and intrinsic buffers are also ``ProxyArray`` objects. ``pos_w`` has shape ``(N, 3)``,
``intrinsic_matrices`` has shape ``(N, 3, 3)``, and camera quaternions have shape ``(N, 4)`` in
``(x, y, z, w)`` order. Set ``update_latest_camera_pose=True`` only when current pose data is needed;
updating it adds frame-query overhead.

Output types
------------

The active renderer validates ``data_types`` and allocates the channel count and data type declared
by its :class:`~isaaclab.renderers.RenderBufferSpec`.

.. list-table:: Common output contracts
:header-rows: 1
:widths: 34 22 44

* - Name
- Channels and type
- Meaning
* - ``rgb`` / ``rgba``
- 3 / 4, ``uint8``
- Low-dynamic-range color
* - ``rgb_hdr``
- 3, ``float32``
- Scene-linear high-dynamic-range color
* - ``albedo``
- 4, ``uint8``
- Material base color
* - ``depth`` / ``distance_to_image_plane``
- 1, ``float32``
- Distance [m] along the camera optical axis
* - ``distance_to_camera``
- 1, ``float32``
- Euclidean distance [m] from the optical center
* - ``normals``
- 3, ``float32``
- Local surface normal ``(x, y, z)``
* - ``motion_vectors``
- 2, ``float32``
- Image-space motion; positive ``x`` is left and positive ``y`` is up
* - ``semantic_segmentation``
- 4 ``uint8`` or 1 ``int32``
- Semantic color or ID per pixel
* - ``instance_segmentation``
- 4 ``uint8`` or 1 ``int32``
- Semantically labeled instance color or ID per pixel
* - ``instance_id_segmentation_fast``
- 4 ``uint8`` or 1 ``int32``
- USD-prim instance color or ID per pixel

``depth`` is an alias of ``distance_to_image_plane``. Colorized segmentation uses RGBA ``uint8``;
non-colorized segmentation uses one ``int32`` ID channel. Label and prim-path mappings are stored in
``camera_data.info[output_name]``.

.. figure:: ../../_static/overview/sensors/camera_rgb.jpg
:align: center
:figwidth: 100%
:alt: RGB camera output

.. figure:: ../../_static/overview/sensors/camera_depth.jpg
:align: center
:figwidth: 100%
:alt: Depth camera output

.. _camera-supported-annotators:

Renderer support
~~~~~~~~~~~~~~~~

The common API does not imply that every renderer produces every output. The current support matrix
is:

.. list-table::
:header-rows: 1
:widths: 38 20 20 22

* - Output
- Isaac RTX
- OVRTX
- Newton Warp
* - ``rgb``, ``rgba``, ``rgb_hdr``
- Yes
- Yes
- Yes
* - ``depth`` and both distance outputs
- Yes
- Yes
- Yes
* - ``normals``
- Yes
- Yes
- Yes
* - ``albedo``
- Isaac Sim 6.0+
- Yes
- Yes
* - ``motion_vectors``
- Yes
- Yes
- No
* - semantic and instance segmentation
- Yes
- Yes
- Yes
* - ``instance_id_segmentation_fast``
- Yes
- No
- No
* - ``simple_shading_*`` modes
- Isaac Sim 6.0+
- Yes
- No

Querying an unsupported output fails during camera initialization. Renderer configuration controls
semantic filters, segmentation colorization, and depth clipping where those options are
backend-specific.

.. figure:: ../../_static/overview/sensors/camera_normals.jpg
:align: center
:figwidth: 100%
:alt: Camera surface-normal output

.. figure:: ../../_static/overview/sensors/camera_semantic.jpg
:align: center
:figwidth: 100%
:alt: Semantic segmentation output

.. figure:: ../../_static/overview/sensors/camera_instance.jpg
:align: center
:figwidth: 100%
:alt: Instance segmentation output

Background color
----------------

When :attr:`~sensors.CameraCfg.background_color` is ``None``, each renderer uses its default
background. Set a normalized RGB tuple to use a solid color for pixels that miss all geometry:

.. code-block:: python

mask_camera = front_camera.replace(background_color=(0.0, 0.0, 0.0))

The setting is per camera. Cameras with renderer-default and solid backgrounds can coexist in one
scene.

Post-render image signal processing
-----------------------------------

:attr:`~sensors.CameraCfg.isp_cfg` optionally applies an image signal processing (ISP) pass to the
renderer's scene-linear HDR output. The shipped implementation is PPISP (Physically Plausible Image
Signal Processing), which applies responsivity, exposure, vignetting, color correction, and a camera
response function before writing ``rgb`` or ``rgba``.

The field accepts:

* ``None`` to disable post-render ISP.
* :class:`~isaaclab_ppisp.PpispCfg` for explicit coefficients or coefficients imported from a USD
camera.
* :class:`~sensors.CameraISPMode` to discover ``ppisp:*`` attributes on a camera prim.

.. code-block:: python

from isaaclab.sensors.camera import CameraCfg, CameraISPMode
from isaaclab_ppisp import PpispCfg

explicit_isp = front_camera.replace(
data_types=["rgb"],
isp_cfg=PpispCfg(inputs={"exposureOffset": 1.5}),
)

discovered_isp = front_camera.replace(
data_types=["rgb"],
isp_cfg=CameraISPMode.AUTO_CAMERA,
)

``AUTO_CAMERA`` checks the first matched camera prim. ``AUTO_ANY`` falls back to the first PPISP
camera anywhere on the stage. Discovery happens once during camera construction.

PPISP is composed by Isaac RTX, OVRTX, and Newton Warp. It requires ``rgb`` or ``rgba`` output. A
static configuration is shared by all cloned views in one camera batch; controller weights may
predict per-view exposure and color parameters, while the remaining coefficients stay shared. ISP
configuration and discovered USD attributes are fixed for the camera lifetime.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Suggestion · Implementation — Rewrite drops documented RTX ISP side effects

The deleted camera page documented that enabling isp_cfg on Isaac RTX/OVRTX force-disables RTX tonemapping and authors a neutral OmniRtxCameraExposureAPI_1 schema on each camera prim, so mixing it with RTX-side exposure authoring is unsupported. That stage-mutating behavior is not restated here or on any other page, and users cannot infer it from the new text. Re-add a short caveat in this section.


Run ``scripts/demos/sensors/ppisp_camera.py`` for a complete PPISP workflow:

.. code-block:: bash

uv run --extra isaacsim python scripts/demos/sensors/ppisp_camera.py \
--renderer newton_renderer --max_steps 60

Performance and validation
--------------------------

Image memory and rendering cost scale with the number of environments, resolution, channel count,
and requested outputs. Start camera-based tasks with a small environment count, verify shapes and
renderer support, and then scale while monitoring GPU memory. Avoid requesting buffers that the task
does not consume.

Tiled rendering batches the cloned views into shared render passes, but it does not remove the memory
cost of the de-tiled outputs or downstream vision models. The camera follows the shared sensor
``update_period`` contract; choose a period that matches the observation cadence instead of rendering
at every physics step by default.

A runnable camera example is available in ``scripts/demos/sensors/cameras.py``:

.. code-block:: bash

uv run --extra isaacsim python scripts/demos/sensors/cameras.py

For saving output to disk, see :doc:`/source/how-to/save_camera_output`. For camera-capacity
estimation, see :doc:`/source/how-to/estimate_how_many_cameras_can_run`.
Loading
Loading