Source code for simvx.graphics.picking.raycast_utils
"""Multi-ray casting helpers for batch intersection tests."""
from __future__ import annotations
import logging
import numpy as np
from .raycast import ray_aabb_intersect
log = logging.getLogger(__name__)
__all__ = ["compute_aabb", "cast_rays_single_hit", "cast_rays_multi_hit"]
[docs]
def compute_aabb(
center: np.ndarray,
half_extents: np.ndarray,
) -> tuple[np.ndarray, np.ndarray]:
"""Compute world-space AABB from center position and half-extents."""
return center - half_extents, center + half_extents
[docs]
def cast_rays_single_hit(
ray_origins: np.ndarray,
ray_direction: np.ndarray,
cubes: list[dict],
) -> np.ndarray:
"""Cast rays against cubes, return first hit cube index per ray.
Returns (N,) array of hit cube indices, -1 for miss.
"""
num_rays = len(ray_origins)
hits = np.full(num_rays, -1, dtype=np.int32)
for i in range(num_rays):
origin = ray_origins[i]
closest_t = float("inf")
for cube in cubes:
is_hit, t = ray_aabb_intersect(
origin,
ray_direction,
cube["aabb_min"],
cube["aabb_max"],
)
if is_hit and 0 <= t < closest_t:
closest_t = t
hits[i] = cube["index"]
return hits
[docs]
def cast_rays_multi_hit(
ray_origins: np.ndarray,
ray_direction: np.ndarray,
cubes: list[dict],
) -> list[list[int]]:
"""Cast rays against cubes, return ALL hit cube indices per ray."""
num_rays = len(ray_origins)
hits: list[list[int]] = [[] for _ in range(num_rays)]
for i in range(num_rays):
origin = ray_origins[i]
for cube in cubes:
is_hit, t = ray_aabb_intersect(
origin,
ray_direction,
cube["aabb_min"],
cube["aabb_max"],
)
if is_hit and t >= 0:
hits[i].append(cube["index"])
return hits