Skip to content

Newton Raycast Sensor#5919

Draft
StafaH wants to merge 1 commit into
isaac-sim:developfrom
StafaH:mh/newton_raycaster
Draft

Newton Raycast Sensor#5919
StafaH wants to merge 1 commit into
isaac-sim:developfrom
StafaH:mh/newton_raycaster

Conversation

@StafaH
Copy link
Copy Markdown
Contributor

@StafaH StafaH commented Jun 2, 2026

Description

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
  • I have added my name to the CONTRIBUTORS.md or my name already exists there

@StafaH StafaH changed the base branch from main to develop June 2, 2026 08:11
@github-actions github-actions Bot added documentation Improvements or additions to documentation isaac-sim Related to Isaac Sim team isaac-mimic Related to Isaac Mimic team infrastructure labels Jun 2, 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.

🤖 Isaac Lab Review Bot

Summary

This PR adds NewtonRayCaster, a ray-cast sensor that queries the live Newton collision model BVH directly (via newton.intersect_ray) rather than parsing and tracking individual USD meshes. The implementation is clean, well-scoped, and follows the existing mixin-based architecture established by the Newton RayCaster. The supporting .pyi stub updates correctly export the new symbols.

Design Assessment

Design is sound. The approach of subclassing BaseRayCaster and overriding _initialize_warp_meshes (no-op) and _update_buffers_impl (Newton BVH query) is the natural extension point. The _NewtonRayCasterMixin provides site-based pose tracking, and the new class adds the Newton-native ray intersection. The separation from the existing mesh-based RayCaster is appropriate since this handles dynamic geometry without per-mesh tracking.

Findings

🟡 Warning: newton.intersect_ray does not respect env_masknewton_ray_caster.py:88

The implementation calls newton.intersect_ray unconditionally for all environments before the _resolve_ray_hits_kernel filters by env_mask. This means rays are cast for environments that don’t need updating (stale ray data from previous frame). While correctness is preserved (the resolve kernel skips masked envs), this is a performance concern for large environment counts with sparse update masks.

Consider gating the intersect_ray call or providing world-mask support if the Newton API allows it.

🟡 Warning: Inconsistent use of self._view_count vs self._num_envsnewton_ray_caster.py:81-82 vs 93

_initialize_rays_impl uses self._view_count to size the _ray_dist and _ray_worlds buffers, but _update_buffers_impl launches kernels with dim=(self._num_envs, self.num_rays). While these values are equal for single-site-per-env sensors, the mixed usage makes the invariant fragile. If multi-site configurations are ever supported, the buffer size and kernel launch dimensions would silently diverge.

🔵 Suggestion: Add max_distance default override to NewtonRayCasterCfgnewton_ray_caster_cfg.py:27

The inherited max_distance defaults to 1e6 meters from RayCasterCfg. For Newton BVH queries against live collision geometry (which is typically much closer range than terrain height scans), a more reasonable default (e.g., 100.0m) would prevent users from accidentally passing enormous distances to the BVH traversal, potentially impacting query performance.

🔵 Suggestion: Docstring for mesh_prim_paths override could be more informativenewton_ray_caster_cfg.py:28

The docstring says "Unused by the Newton ray-caster" but doesn't explain why or what replaces it. A brief note like "Not used because rays are cast against the Newton model's collision BVH directly, which handles all geometry without explicit mesh registration" would help users understand the design.

Test Coverage

  • New code: No dedicated tests included in this PR for NewtonRayCaster.
  • Gaps: Integration test validating that NewtonRayCaster produces correct hit positions against known geometry would strengthen confidence. At minimum, a smoke test ensuring the sensor initializes and produces non-inf hits with a simple scene would catch regressions.

Verdict

Minor fixes needed

The implementation is architecturally correct and follows established patterns well. The env_mask performance concern and the _view_count/_num_envs fragility are worth addressing but are not blocking. Adding basic test coverage would significantly strengthen this PR.


def _update_buffers_impl(self, env_mask: wp.array):
"""Fills the buffers of the sensor data."""
self._update_ray_infos(env_mask)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Warning: newton.intersect_ray is called for ALL environments regardless of env_mask.

The _update_ray_infos(env_mask) only updates ray starts/directions for active envs, but newton.intersect_ray then casts rays for all num_envs * num_rays entries (including stale data for masked envs). While the downstream _resolve_ray_hits_kernel correctly skips masked envs, this wastes BVH traversal work.

If the Newton API supports a world-mask or if you can slice the flat arrays to only include active environments, this could be a meaningful optimization for large env counts with sparse updates.

# Flat (zero-copy) ray views for newton.intersect_ray.
self._ray_starts_w_flat = self._ray_starts_w.flatten()
self._ray_directions_w_flat = self._ray_directions_w.flatten()
self._ray_dist = wp.empty(num_envs * num_rays, dtype=wp.float32, device=self._device)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Warning: Mixed _view_count / _num_envs usage.

Here _view_count is used to size buffers:

num_envs, num_rays = self._view_count, self.num_rays

But in _update_buffers_impl (line 93), kernel launches use self._num_envs:

dim=(self._num_envs, self.num_rays)

For single-site sensors these are equal, but the inconsistency is fragile. Consider using one consistently (preferably self._num_envs since that's what the base class uses for kernel launches, and document that _view_count == _num_envs is a precondition).

class_type: type[NewtonRayCaster] | str = "{DIR}.newton_ray_caster:NewtonRayCaster"

mesh_prim_paths: list[str] = []
"""Unused by the Newton ray-caster."""
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 Suggestion: More informative docstring.

Suggested change
"""Unused by the Newton ray-caster."""
mesh_prim_paths: list[str] = []
"""Not used by the Newton ray-caster; rays are cast directly against the Newton
model's collision BVH which covers all geometry without explicit mesh registration."""

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.

Newton Ray-Caster Review

Clean, well-structured implementation that leverages the existing _NewtonRayCasterMixin for pose tracking and adds BVH-based raycasting via newton.intersect_ray. The design correctly bypasses USD mesh parsing and integrates smoothly with the BaseRayCaster lifecycle. A few items to address:

Findings

1. newton.intersect_ray ignores env_mask — unnecessary compute for inactive environments

File: source/isaaclab_newton/isaaclab_newton/sensors/ray_caster/newton_ray_caster.py (L89–96)
Severity: Medium (Performance)

newton.intersect_ray is called with the full flat ray buffer regardless of env_mask. For environments that are masked out (e.g., after reset or when the sensor update period hasn't elapsed), rays are still cast and distances computed, only to be discarded by _resolve_ray_hits_kernel. In large-scale training with staggered resets, this wastes significant GPU cycles.

Suggested fix: Either compact the ray inputs to only active environments before the call, or check if Newton supports a world-mask parameter to skip inactive worlds.

2. No NaN guard in _resolve_ray_hits_kernel — degenerate rays could silently produce garbage hit positions

File: source/isaaclab_newton/isaaclab_newton/sensors/ray_caster/newton_ray_caster.py (L49–54)
Severity: Low–Medium (Robustness)

The kernel checks dist < 0.0 and dist > max_dist to classify misses, but does not guard against NaN. If newton.intersect_ray returns NaN for degenerate ray directions (e.g., zero-length direction vectors), both comparisons evaluate to False, causing the kernel to compute ray_start + NaN * direction and store a garbage position instead of inf.

Suggested fix:

if dist < 0.0 or dist > max_dist or wp.isnan(dist):
    ray_hits_w[env, ray] = wp.vec3f(wp.inf, wp.inf, wp.inf)

Or use dist != dist as an idiomatic NaN check if wp.isnan is unavailable in kernel context.

3. No unit tests for the new sensor

Severity: Medium (Test Coverage)

The PR adds NewtonRayCaster and NewtonRayCasterCfg but no corresponding test file. Even a basic test verifying:

  • Instantiation with a simple pattern config
  • Ray hit output shape/dtype correctness
  • Miss encoding (inf) for rays that don't intersect anything
  • Behavior with enable_global_world=False

…would prevent regressions as the Newton backend evolves.

4. mesh_prim_paths = [] — consider raising on accidental user assignment

File: source/isaaclab_newton/isaaclab_newton/sensors/ray_caster/newton_ray_caster_cfg.py (L27)
Severity: Low (UX)

The docstring says "Unused by the Newton ray-caster," but if a user accidentally provides paths (e.g., copy-pasting from a standard RayCasterCfg), the paths are silently ignored since _initialize_warp_meshes is a no-op. A __post_init__ validation that warns or raises when mesh_prim_paths is non-empty would prevent user confusion.

5. _ray_worlds assumes env-index ≡ Newton world-index without runtime assertion

File: source/isaaclab_newton/isaaclab_newton/sensors/ray_caster/newton_ray_caster.py (L80–81)
Severity: Low (Robustness)

ray_worlds = np.repeat(np.arange(num_envs, dtype=np.int32), num_rays)

The inline comment explains the assumption ("env index == world index"), but if this invariant is ever violated (e.g., partial environment loading or non-zero-based world indexing), rays would silently cast against wrong worlds. Consider adding a debug assertion at initialization that NewtonManager world count matches num_envs.


Overall: Solid implementation that follows established patterns in the codebase. The main suggestions are around defensive programming (NaN handling, assumption validation) and ensuring test coverage exists before merge. The performance concern (#1) is worth tracking but may be acceptable for an initial implementation if Newton doesn't yet support masked raycasting.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation infrastructure isaac-mimic Related to Isaac Mimic team isaac-sim Related to Isaac Sim team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant