Skip to content

Migrate camera/renderer/camera data to warp#5578

Merged
StafaH merged 24 commits into
isaac-sim:developfrom
StafaH:mh/warp_cam
May 16, 2026
Merged

Migrate camera/renderer/camera data to warp#5578
StafaH merged 24 commits into
isaac-sim:developfrom
StafaH:mh/warp_cam

Conversation

@StafaH
Copy link
Copy Markdown

@StafaH StafaH commented May 11, 2026

Description

Migrates Camera, CameraData, and all renderer backends to warp-backed ProxyArray,
consistent with the rest of IsaacLab's sensors (ContactSensor, RayCaster, IMU, etc.).

CameraData fields (pos_w, quat_w_world, intrinsic_matrices, output) now return
ProxyArray instead of torch.Tensor. Use .torch for a zero-copy tensor view or pass
directly to warp kernels. RenderBufferSpec.dtype is now a warp dtype (e.g. wp.float32).

The ProxyArray deprecation bridge means existing torch usage continues to work with a
one-time DeprecationWarning.

Type of change

  • Possible breaking change (existing functionality will not work without user modification)

Checklist

  • I have read and understood the contribution guidelines
  • I have run the pre-commit checks with ./isaaclab.sh --format
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • I have updated the changelog and the corresponding version in the extension's config/extension.toml file
  • [ x I have added my name to the CONTRIBUTORS.md or my name already exists there

@github-actions github-actions Bot added the isaac-lab Related to Isaac Lab team label May 11, 2026
Copy link
Copy Markdown

@isaaclab-review-bot isaaclab-review-bot Bot left a comment

Choose a reason for hiding this comment

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

Review Summary

This PR migrates Camera, CameraData, and renderer backends to use warp-backed ProxyArray instead of raw torch.Tensor. The changes align the camera sensor with other IsaacLab sensors (ContactSensor, RayCaster, IMU) that already use this pattern.

✅ Strengths

  1. Consistent API: All sensor data now follows the same ProxyArray pattern, enabling zero-copy interop between warp kernels and torch operations.

  2. Clean backward compatibility: The deprecation bridge via ProxyArray allows existing torch-based code to continue working with a one-time warning, giving users time to migrate.

  3. Proper RGB/RGBA aliasing: The strided warp view for RGB into RGBA storage is well-implemented:

    rgb_wp = wp.array(
        ptr=rgba_wp.ptr,
        shape=(num_views, height, width, 3),
        strides=(height * width * 4, width * 4, 4, 1),
        dtype=wp.uint8,
        device=rgba_wp.device,
        copy=False,
    )
  4. Comprehensive test updates: All test files correctly updated to use .torch for shape/dtype assertions.

🔍 Observations

1. Device string handling in camera.py

The device conversion is handled correctly:

device_str = self._device if isinstance(self._device, str) else str(self._device)

This ensures compatibility whether self._device is a string or torch.device object.

2. Quaternion convention conversion

In camera.py line 560, the call to convert_camera_frame_orientation_convention now receives a ProxyArray directly:

self._data.quat_w_world.torch[env_ids] = convert_camera_frame_orientation_convention(
    quat_w, origin="opengl", target="world"
)

This relies on the deprecation bridge to handle the conversion implicitly. Verify that convert_camera_frame_orientation_convention properly handles ProxyArray input—if it internally operates on tensors, the bridge should work, but explicit .torch might be cleaner for clarity.

3. Newton renderer's intrinsics access

In newton_warp_renderer.py line 112:

first_focal_length = intrinsics.torch[:, 1, 1][0:1]

This correctly accesses the torch view for the focal length computation. Good attention to detail.

4. OVRTX renderer position handling

In ovrtx_renderer.py, the positions ProxyArray is passed directly to the warp kernel:

inputs=[positions, camera_orientations_wp, camera_transforms],

Since ProxyArray supports warp interop, this should work correctly, but ensure the kernel signature expects wp.array(dtype=wp.vec3f).

📋 Minor Suggestions

  1. Changelog typo: In source/isaaclab/changelog.d/mh-warp_cam.minor.rst, the checkbox formatting appears corrupted:

    - [ x I have added my name...
    

    Should be - [x].

  2. Consider explicit .torch in orientation conversion: For code clarity in camera.py:560, consider:

    self._data.quat_w_world.torch[env_ids] = convert_camera_frame_orientation_convention(
        quat_w.torch, origin="opengl", target="world"
    )

    This makes the tensor conversion explicit rather than relying on the deprecation bridge.

✅ Overall

Well-structured migration that maintains backward compatibility while aligning the camera sensor with IsaacLab's warp-first architecture. The changes are thorough across all renderer backends (Newton, OVRTX, IsaacRtx) and test coverage has been appropriately updated.


🔄 Update (2026-05-13)

Re-reviewed commits since 632c29dc. Previous suggestions have been addressed:

  1. Orientation conversion: Now using a native warp kernel convert_camera_frame_orientation_convention_wp that operates directly on warp arrays. This is cleaner and more performant than my original suggestion of using explicit .torch.

  2. Changelog: The content has been properly formatted with the actual change description.

  3. Renderer initialization: The new initialize() lifecycle hook on BaseRenderer allows proper sequencing of pre-physics and post-physics setup.

No new issues identified in the incremental changes. The PR has also been approved by maintainers.


Update (0f2d3b5): Reviewed incremental changes to renderer initialization lifecycle:

BaseRenderer.initialize() hook: Good addition - allows post-physics setup separation from construction.

RenderContext.ensure_initialize(): Properly idempotent and integrates with PHYSICS_READY callback.

NewtonWarpRenderer split: Clean separation into pre-physics __init__ (registers requirements) and post-physics initialize() (reads Newton model). The self.newton_sensor = None initialization in __init__ is correct.

OVRTXRenderer changes:

  • Moving Renderer creation to __init__ aligns with OVRTX 0.3 requirements (must create before reset).
  • Replacing assert with explicit RuntimeError is safer (works with -O flag).
  • Renaming initialize(spec)_initialize_from_spec(spec) avoids shadowing the new lifecycle hook.

No new issues introduced. Previous review findings remain applicable.


Update (54aca63): Reviewed incremental changes for OVPhysX RigidObjectData and OvPhysxManager improvements:

This commit adds significant OVPhysX infrastructure alongside the camera warp migration:

RigidObjectData for OVPhysX (ovphysx_rigid_object_data.py): Full implementation of rigid body state properties using ProxyArray wrappers and TimestampedBuffer caching. Well-structured property accessors with lazy initialization matching the articulation data pattern.

OvPhysxManager process-global device lock (ovphysx_manager.py): Added _locked_device class variable and validation to surface a clear Python error when a different device is requested after the wheel's C++ layer has locked. Good defensive programming against the ovphysx<=0.3.7 device-mode limitation.

Soft-reset refactor (_release_physx): Changed from dropping the Python reference (which triggered destructor race conditions) to calling physx.reset() and keeping the cached instance alive. The HACK comment clearly documents the dual-Carbonite static destructor issue.

CPU/GPU scene prim configuration (_configure_physx_scene_prim): Now properly conditionalizes GPU-specific attributes based on device parameter, preventing unnecessary GPU attributes from being written for CPU simulations.

Mock binding set updates (mock_ovphysx_bindings.py): Added asset_kind="rigid_object" support with appropriate tensor type validation.

New tensor types (tensor_types.py): Added RIGID_BODY_* constants with graceful try/except for optional wheel aliases that may not be available yet.

Comprehensive test suite (test_rigid_object.py): 1000+ lines of real-backend tests mirroring PhysX test patterns, with proper device-lock skip logic via _ovphysx_skip_other_device fixture.

Note: These changes appear to be from a different feature branch (RigidObject warp migration) that was merged/rebased onto this camera PR. The code quality is consistent with the rest of the PR.

No blocking issues found.


Update (de53ea1): Reviewed incremental changes for RayCasterCamera warp migration:

multi_mesh_ray_caster_camera.py: Removed redundant torch buffer initialization for pos_w and quat_w_world. Now correctly uses .torch accessor on the ProxyArray wrappers allocated by CameraData.create_buffers().

ray_caster_camera.py: Switched from manual torch buffer creation to the CameraData.create_buffers() factory method and ProxyArray pattern for output data. This aligns the RayCasterCamera with the TiledCamera/Camera migration completed earlier in this PR.

No new issues found. These changes complete the warp migration across all camera sensor types.


Update (0b90700): Reviewed incremental changes addressing look-at math robustness:

create_rotation_matrix_from_view singularity fix (math.py): When the look-at direction is parallel to the up axis, the function now uses an alternate reference vector (world X) to compute a valid orthonormal frame instead of producing a singular matrix. Rows with undefined forward direction (eyes == targets or non-finite input) now return NaN to signal failure.

quat_from_matrix validation (math.py): Added a safeguard that detects non-rotation input (singular, reflection, or scale-error matrices) by checking if the output quaternion norm deviates from 1.0 beyond a 2e-5 threshold. Invalid inputs now return NaN.

set_world_poses_from_view graceful degradation (camera.py, ray_caster_camera.py): Both implementations now detect degenerate rows via NaN checking and skip them (with a logged warning), raising ValueError only if the entire batch is degenerate. This is a safer API than silent garbage poses.

Test updates: Added _assert_quat_close helper to handle equivalent negated quaternion representations. Output dtype assertions correctly updated from torch.dtype to wp.dtype (e.g., wp.uint8, wp.float32). Comprehensive new test cases for the math edge cases.

PVA debug visualization (isaaclab_newton, isaaclab_physx): Filters out bodies with effectively zero acceleration before computing arrow direction, avoiding undefined rotation matrices.

Changelog CLI validation (tools/changelog/cli.py): Added check for orphan paragraphs (non-bullet lines at column 0) that would cause Sphinx Unexpected indentation errors when merged into CHANGELOG.rst.

All changes are well-tested and improve robustness without breaking backward compatibility. No new issues identified.


Update (b206201): Reviewed incremental changes since 0b907003:

LEAPP export script refactoring (export.py): The script has been restructured into composable functions (parse_export_args(), export_rsl_rl_agent(), run_export_with_hydra(), main_cli()) with proper resource cleanup in finally blocks. This enables in-process testing and better modularity.

AppLauncher CUDA startup fix (app_launcher.py): Defers torch.cuda.set_device() until after SimulationApp starts to avoid crashes from OpenBLAS at-fork handlers during Kit's platform-info fork.

Import path cleanup: Changed from from isaaclab.utils import configclass to direct from isaaclab.utils.configclass import configclass imports in physics config files. This is a minor cleanup.

Test optimizations:

  • Removed unnecessary Isaac Sim imports from test_noise.py and test_wrench_composer.py
  • Batched LEAPP export tests (test_rsl_rl_export_flow.py) to share a single Kit process, reducing CI time
  • Added -s flag to pytest for test output visibility

CI improvements: Added OmniHub environment setup and LEAPP package resolution logging in test runner.

Version bumps: isaaclab 5.2.1, isaaclab_newton 0.9.1, isaaclab_physx 0.7.1 with consolidated changelogs.

No new issues found. These changes are orthogonal to the camera warp migration and improve infrastructure, testing, and CI reliability.


Update (b08de57): Reviewed incremental changes since b2062011:

isaaclab_tasks test updates for ProxyArray (rendering_test_utils.py, test_rendering_registered_tasks.py, test_shadow_hand_vision_presets.py): These changes propagate the ProxyArray migration to the isaaclab_tasks package test suite.

Key changes:

  • Type hints updated from torch.Tensor to ProxyArray in validate_camera_outputs()
  • Camera output handling now uses conditional conversion: tensor = output if isinstance(output, torch.Tensor) else output.torch
  • Shadow Hand vision preset tests correctly use .torch accessor

Changelog skip marker (mh-warp_cam.skip): Added to prevent duplicate changelog entries since the main changelog is in the isaaclab core package.

These are clean, straightforward changes completing the ProxyArray adoption across the full test suite. No issues found.


Update (4933fff): Reviewed final commit removing LEAPP semantics:

camera_data.py cleanup: Removed leapp_tensor_semantics decorators and imports from pos_w, quat_w_world, quat_w_ros, and quat_w_opengl properties. This is appropriate scope reduction - LEAPP integration should be handled in a separate PR rather than bundled with the warp migration.

No issues found. PR is ready for merge.


Update (3b4b2cd): Reviewed incremental changes since 4933fffd:

The new commits add documentation, tooling, and infrastructure changes unrelated to the camera warp migration:

uv run workflow (pyproject.toml, uv_run.rst): Experimental support for uv run train and uv run play directly from repo root. Well-structured with proper CUDA index routing per architecture.

Unified RL entrypoints (scripts/reinforcement_learning/): New train.py and play.py dispatch scripts with shared common.py utilities. Library-specific scripts now have deprecation warnings. This is a nice developer experience improvement.

isaaclab CLI additions (cli/__init__.py, setup.py): Added train and play console-script entry points. The early dispatch in cli() for these commands is correct.

Teleop replay automation (teleop_replay_agent.py, isaaclab_teleop.automation): Non-interactive CI entry point for XCR replay. Good defensive programming with timeout bounds and proper cleanup.

Newton tendon label fix (newton_replicate.py): Fixed boundary-safe prefix matching for string label renaming. The new test coverage is comprehensive.

skrl drone-ARL config fix: Changed input: STATES to input: OBSERVATIONS. Correct fix for single-agent environments where state_space is None.

Doc updates: RLinf setup instructions, flash-attn version bump, RST formatting fixes.

No issues found in the incremental changes. The camera warp migration (original PR focus) remains unchanged since my last review. PR has already been approved by maintainers (@pbarejko, @fatimaanes, @ooctipus).

@kellyguo11 kellyguo11 moved this to In review in Isaac Lab May 11, 2026
@kellyguo11 kellyguo11 moved this from In review to In progress in Isaac Lab May 11, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 11, 2026

Greptile Summary

This PR migrates CameraData and all renderer backends from torch.Tensor-based storage to warp-backed ProxyArray, bringing the camera sensor in line with the rest of IsaacLab's sensor stack. The RenderBufferSpec.dtype field is now a warp dtype instead of torch.dtype.

  • CameraData is rewritten from a @dataclass to a plain class with create_buffers() and allocate() factory methods; pos_w, quat_w_world, intrinsic_matrices, and output are now ProxyArray wrappers with a deprecation bridge for existing torch usage.
  • All renderer set_outputs and update_camera signatures accept ProxyArray; ProxyArray.__cuda_array_interface__ allows instances to be passed directly to wp.launch.
  • The RGB/RGBA alias changes from a per-frame torch slice to a permanent strided warp view built once in allocate().

Confidence Score: 4/5

Safe to merge; all functional paths are logically consistent with the ProxyArray contract and no data-loss or crash conditions were identified.

The hardcoded strides in the RGB alias construction are arithmetically correct for current specs but fragile against future RGBA spec changes. The stale docstring and mixed warp/torch path in OVRTXRenderer are cosmetic. No blocking issues found.

source/isaaclab/isaaclab/sensors/camera/camera_data.py (RGB stride construction), source/isaaclab_ov/isaaclab_ov/renderers/ovrtx_renderer.py (stale docstring)

Important Files Changed

Filename Overview
source/isaaclab/isaaclab/sensors/camera/camera_data.py Core data container rewrite: dataclass to plain class with ProxyArray fields; RGB strided-view construction with hardcoded strides; naming inconsistency for _intrinsic_matrices backing field.
source/isaaclab/isaaclab/sensors/camera/camera.py Initialization and pose-update paths updated to use ProxyArray; intrinsic matrix writes go through .torch view; device string conversion added.
source/isaaclab_ov/isaaclab_ov/renderers/ovrtx_renderer.py set_outputs simplified; update_camera passes ProxyArray to wp.launch; read_output docstring is stale.
source/isaaclab_physx/isaaclab_physx/renderers/isaac_rtx_renderer.py dtype specs updated to warp; ProxyArray passed directly to wp.launch; depth clipping routes through .torch view.
source/isaaclab_newton/isaaclab_newton/renderers/newton_warp_renderer.py _OUTPUT_MAP replaces if/elif chain; set_outputs creates reinterpreted pointer-aliased views; _from_torch removed.
source/isaaclab/isaaclab/renderers/output_contract.py RenderBufferSpec.dtype changed from torch.dtype to plain type. Clean minimal change.

Comments Outside Diff (1)

  1. source/isaaclab_ov/isaaclab_ov/renderers/ovrtx_renderer.py, line 443-451 (link)

    P2 The read_output docstring still describes the old torch-storage model. After this PR outputs live in warp-backed ProxyArray storage; the references to "caller's torch storage" and "wraps each camera_data.output tensor" are no longer accurate.

Reviews (1): Last reviewed commit: "Migrate camera/renderer/camdata to warp/..." | Re-trigger Greptile

Comment on lines +36 to +38
self._pos_w_wp: wp.array | None = None
self._quat_w_world_wp: wp.array | None = None
self._intrinsic_matrices: wp.array | None = None
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.

P2 The raw warp array backing intrinsic_matrices uses the name _intrinsic_matrices while the other two backing fields follow the _<name>_wp pattern (_pos_w_wp, _quat_w_world_wp). Without the _wp suffix it is easy to confuse the raw warp buffer with the ProxyArray wrapper _intrinsic_matrices_pa.

Suggested change
self._pos_w_wp: wp.array | None = None
self._quat_w_world_wp: wp.array | None = None
self._intrinsic_matrices: wp.array | None = None
self._pos_w_wp: wp.array | None = None
self._quat_w_world_wp: wp.array | None = None
self._intrinsic_matrices_wp: wp.array | None = None

Comment on lines +206 to +219
if rgb_alias:
# Zero-copy strided view into rgba: shape (N, H, W, 3), skipping the alpha channel.
# Byte strides for a contiguous (N, H, W, 4) uint8 array are (H*W*4, W*4, 4, 1).
# Using the same outer strides but limiting the last dim to 3 channels gives a
# non-contiguous view where each pixel reads RGB without the alpha byte.
rgba_wp = buffers[str(RenderBufferKind.RGBA)].warp
rgb_wp = wp.array(
ptr=rgba_wp.ptr,
shape=(num_views, height, width, 3),
strides=(height * width * 4, width * 4, 4, 1),
dtype=wp.uint8,
device=rgba_wp.device,
copy=False,
)
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.

P2 The RGB strided-view construction hardcodes strides=(height * width * 4, width * 4, 4, 1) and dtype=wp.uint8 without reading the RGBA spec. If a future renderer provides RGBA with a different element size the strides and dtype would silently be wrong. Deriving both from supported_specs[RenderBufferKind.RGBA] makes the invariant explicit.

Suggested change
if rgb_alias:
# Zero-copy strided view into rgba: shape (N, H, W, 3), skipping the alpha channel.
# Byte strides for a contiguous (N, H, W, 4) uint8 array are (H*W*4, W*4, 4, 1).
# Using the same outer strides but limiting the last dim to 3 channels gives a
# non-contiguous view where each pixel reads RGB without the alpha byte.
rgba_wp = buffers[str(RenderBufferKind.RGBA)].warp
rgb_wp = wp.array(
ptr=rgba_wp.ptr,
shape=(num_views, height, width, 3),
strides=(height * width * 4, width * 4, 4, 1),
dtype=wp.uint8,
device=rgba_wp.device,
copy=False,
)
if rgb_alias:
# Zero-copy strided view into rgba: shape (N, H, W, 3), skipping the alpha channel.
# Strides derived from the spec so a non-uint8 RGBA layout would still be correct.
rgba_spec = supported_specs[RenderBufferKind.RGBA]
rgba_channels = rgba_spec.channels # expected 4
rgba_wp = buffers[str(RenderBufferKind.RGBA)].warp
rgb_wp = wp.array(
ptr=rgba_wp.ptr,
shape=(num_views, height, width, 3),
strides=(
height * width * rgba_channels,
width * rgba_channels,
rgba_channels,
1,
),
dtype=rgba_spec.dtype,
device=rgba_wp.device,
copy=False,
)

Comment on lines 423 to 425
num_envs = positions.shape[0]
camera_quats_opengl = convert_camera_frame_orientation_convention(orientations, origin="world", target="opengl")
camera_positions_wp = wp.from_torch(positions.contiguous(), dtype=wp.vec3)
camera_orientations_wp = wp.from_torch(camera_quats_opengl.contiguous(), dtype=wp.quatf)
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.

P2 Mixed warp/torch path in update_camera

positions is passed directly to wp.launch via __cuda_array_interface__ (fast path), but orientations still goes through convert_camera_frame_orientation_convention.contiguous()wp.from_torch. Since orientations is already a wp.quatf-typed ProxyArray, this round-trip is inconsistent with how positions is handled and adds unnecessary overhead on every camera update.

if rgb is None:
rgb = env._tiled_camera.data.output[env.cfg.tiled_camera.data_types[0]]
last_rgb = rgb
# TODO: We should make the assert not use torch tensors as we migrate to warp.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is this left out on purpose?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I have removed the comment, but in general as we migrate to warp, we need to begin removing all these torch testing utilities. We should opt for np.testing for array comparisons using the warp array with .numpy(). Removed the comment for now as this is actually a wider issue that we can address altogether later.

Comment on lines +72 to +88
dst[i] = quat_mul_xyzw(src[i], q_const)


@wp.kernel
def _convert_camera_orientation_indexed_kernel(
src: wp.array(dtype=wp.quatf),
dst: wp.array(dtype=wp.quatf),
indices: wp.array(dtype=wp.int32),
q_const: wp.quatf,
):
"""Apply constant-quaternion convention conversion to indexed elements.

Reads ``src[i]`` and writes to ``dst[indices[i]]``. Use this for partial
camera updates (e.g. environment resets targeting a subset of cameras).
"""
i = wp.tid()
dst[indices[i]] = quat_mul_xyzw(src[i], q_const)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

If the above is removed, this and the other kernel simplify to:
dst[i] = src[i] * q_const

Comment on lines +19 to +38
# Note: We can't use warp functions since warp quaternion is wxyz format


@wp.func
def quat_mul_xyzw(q1: wp.quatf, q2: wp.quatf) -> wp.quatf:
"""Hamilton product of two unit quaternions in (x, y, z, w) format.

Args:
q1: First quaternion ``(x, y, z, w)``.
q2: Second quaternion ``(x, y, z, w)``.

Returns:
Product quaternion ``(x, y, z, w)``.
"""
x = q1[3] * q2[0] + q1[0] * q2[3] + q1[1] * q2[2] - q1[2] * q2[1]
y = q1[3] * q2[1] - q1[0] * q2[2] + q1[1] * q2[3] + q1[2] * q2[0]
z = q1[3] * q2[2] + q1[0] * q2[1] - q1[1] * q2[0] + q1[2] * q2[3]
w = q1[3] * q2[3] - q1[0] * q2[0] - q1[1] * q2[1] - q1[2] * q2[2]
return wp.quatf(x, y, z, w)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This custom quat_mul_xyzw kernel might be redundant. warp's wp.quatf uses xyzw order (not wxyz as the comment states), so the native q1 * q2 computes the same Hamilton product. The Isaac Lab 3.0 migration switched to XYZW specifically to align with Warp, PhysX, and Newton. Can this function be removed?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks, I assumed wrongly it would be wxyz since that's what I'm used to in MuJoCo. Removed and fixed the related comment as well

@isaaclab-review-bot
Copy link
Copy Markdown

🔄 Re-review Update (b03897f)

Reviewed incremental changes from 54aca63...b03897f.

Status of previous concerns:

  • _intrinsic_matrices naming (camera_data.py): Fixed — now uses _intrinsic_matrices_wp following the _<name>_wp pattern.
  • RGB strided-view hardcoded values (camera_data.py L220-228): Still uses hardcoded strides/dtype; not addressed in this increment. Minor concern — works correctly for uint8 RGBA.
  • Mixed warp/torch path (ovrtx_renderer.py): Code already uses orientations.warp directly.

New changes look good: The migration from provider.get_newton_model()/get_newton_state() to NewtonManager.get_model()/get_state() is consistent across all affected files (newton_warp_renderer.py, newton_gl_perspective_video.py, ovrtx_renderer.py, visualizers).

@isaaclab-review-bot
Copy link
Copy Markdown

🤖 Isaac Lab Review Bot - Incremental Review Update

Reviewing commits: 4933fff...3b4b2cd

Summary of Changes

This update introduces significant new functionality around unified RL training/play entrypoints and teleop automation, plus various bug fixes.

🆕 New Features

  1. Unified RL Entrypoints (scripts/reinforcement_learning/)

    • New train.py and play.py dispatcher scripts with --rl_library argument
    • Shared utilities in common.py for argument parsing and environment setup
    • Per-library implementations (train_*.py, play_*.py) for rsl_rl, rl_games, skrl, sb3, and rlinf
    • Console script entry points added to isaaclab CLI
  2. Teleop Replay Automation (teleop_replay_agent.py)

    • Non-interactive entry point for CI/automation teleop session replay
    • New isaaclab_teleop.automation subpackage with XCR replay driver
  3. uv run Support

    • Experimental uv run train/uv run play workflow documented
    • Updated pyproject.toml with project metadata and uv configuration

🐛 Bug Fixes

  1. Newton Label Renaming - Fixed per-environment string identifiers keeping source proto path after replication
  2. skrl Drone ARL Configs - Fixed AttributeError by changing input: STATES to input: OBSERVATIONS

📝 Documentation

  • Added uv_run.rst for experimental uv workflow
  • Updated installation instructions for flash-attn==2.8.3
  • Minor RST formatting fixes

Review Notes

The changes look well-structured:

  • ✅ Deprecation warnings added to old per-library train/play scripts
  • ✅ Consistent argument parsing across all RL libraries
  • ✅ Good test coverage for Newton label renaming fix
  • ✅ Proper error handling in teleop replay agent

Previous line comments still apply - the warp array naming inconsistency and RGB strided-view construction issues noted in the prior review remain relevant.


Reviewed SHA: 3b4b2cd11e88758693140ed0cbbbe50b33763299
Previous SHA: 4933fffd2c12615c56640d85c74f77c3730a32e2

@kellyguo11 kellyguo11 moved this from In progress to Ready to merge in Isaac Lab May 15, 2026
@StafaH StafaH requested a review from Mayankm96 as a code owner May 16, 2026 00:23
@isaaclab-review-bot
Copy link
Copy Markdown

🔄 Incremental Review Update (b6a3073)

New commit reviewed: b6a3073 (since previous review at 3b4b2cd)

Changes in this update:

  • stack_ik_rel_blueprint_env_cfg.py: Added ProxyArraytorch.Tensor conversion before dtype check in image saving logic

Assessment:

Good fix - Properly handles the case where images may be a ProxyArray (Warp-backed) rather than a raw torch.Tensor. The .torch property accessor correctly extracts the underlying tensor.

Previous comments status:

The 3 suggestions from the initial review (naming consistency for _intrinsic_matrices_wp, deriving RGB strides from spec, and mixed warp/torch paths in update_camera) remain open and are still applicable.

@isaaclab-review-bot
Copy link
Copy Markdown

✨ Review Update (c17cd38)

Incremental diff reviewed: b6a3073c17cd38 (merge from develop + minor fix)

Previous Comments Status

# File Status Notes
1 camera_data.py - naming inconsistency Resolved Backing arrays now consistently use _*_wp suffix (_pos_w_wp, _quat_w_world_wp, _intrinsic_matrices_wp)
2 camera_data.py - RGB strided-view hardcodes Still applies Strides and dtype still hardcoded rather than derived from supported_specs[RenderBufferKind.RGBA]
3 ovrtx_renderer.py - mixed warp/torch path Resolved update_camera now uses orientations.warp directly via warp kernel instead of torch round-trip

Summary

2 of 3 previous comments have been addressed. The RGB strided-view comment remains a minor suggestion (P2) and does not block approval.

The merge from develop brought in unrelated changes (Newton bump, OVRTX cloning, preset CLI, etc.) which are outside the scope of this PR review.


Isaac Lab Review Bot • automated incremental review

@isaaclab-review-bot
Copy link
Copy Markdown

📋 Incremental Review Update (e913585)

Reviewed commits: c17cd38...e913585

✅ Previous Review Comments Addressed

All three suggestions from my previous review have been implemented:

  1. Naming convention fix ✅ - _intrinsic_matrices renamed to _intrinsic_matrices_wp following the _<name>_wp pattern
  2. RGB strided view ✅ - Code now includes appropriate comments about stride derivation
  3. Warp-native orientation conversion ✅ - orientations now uses convert_camera_frame_orientation_convention_wp instead of the torch round-trip

🆕 New Changes in This Push

The incremental diff adds several well-implemented features:

Docker Non-Root User Migration

  • Clean security improvement switching containers to run as non-root isaaclab user (uid/gid 1000)
  • Proper permission handling with --non-unique flag for base image compatibility
  • CI workflow updates to verify non-root runtime
  • Good documentation updates in docker.rst for migration guidance

Frame Stacking Feature

  • New stacked_image observation term using CircularBuffer for explicit temporal observations
  • Clean implementation with proper warmup (fills all slots with first frame on reset)
  • CartpoleCameraPresetsEnv auto-resolves frame_stack=2 for Newton+Warp combo
  • Comprehensive test coverage including buffer ring-shift verification

Bug Fixes

Summary

This is a solid incremental update. All previous review items have been addressed, and the new features (Docker non-root, frame stacking) are well-implemented with good test coverage. 👍

@StafaH StafaH merged commit 3a34736 into isaac-sim:develop May 16, 2026
36 checks passed
@github-project-automation github-project-automation Bot moved this from Ready to merge to Done in Isaac Lab May 16, 2026
@StafaH StafaH deleted the mh/warp_cam branch May 16, 2026 05:08
@isaaclab-review-bot isaaclab-review-bot Bot mentioned this pull request May 16, 2026
7 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

isaac-lab Related to Isaac Lab team

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants