Source code for unisim.backend.motrix_camera
from __future__ import annotations
from collections.abc import Mapping, Sequence
from dataclasses import dataclass
from typing import Any
import numpy as np
from unisim.backend.base import CameraCfg
[docs]
@dataclass(frozen=True)
class MotrixTrackingCamera:
env_idx: int
distance: float
elevation: float
azimuth: float
[docs]
@dataclass(frozen=True)
class MotrixCameraView:
lookat: list[float]
distance: float
elevation: float
azimuth: float
tracking: MotrixTrackingCamera | None = None
[docs]
def render_offsets(num_envs: int, spacing: float, offset_mode: str = "grid") -> list[list[float]]:
if offset_mode == "zero":
return [[0.0, 0.0, 0.0] for _ in range(num_envs)]
if offset_mode != "grid":
raise ValueError(f"Unsupported Motrix render_offset_mode: {offset_mode!r}")
cols = int(np.ceil(np.sqrt(num_envs)))
offsets = []
for i in range(num_envs):
row = i // cols
col = i % cols
offsets.append([col * spacing, row * spacing, 0.0])
return offsets
[docs]
def tracking_camera_lookat(
base_positions: np.ndarray,
tracking_camera: MotrixTrackingCamera,
offsets: np.ndarray,
) -> list[float]:
base_pos = np.asarray(base_positions[tracking_camera.env_idx], dtype=np.float64)
render_offset = np.asarray(offsets[tracking_camera.env_idx], dtype=np.float64)
lookat = base_pos + render_offset
return [float(lookat[0]), float(lookat[1]), float(lookat[2])]
[docs]
def resolve_system_camera_view(
num_envs: int,
base_positions: np.ndarray | None,
offsets: Sequence[Sequence[float]],
camera_kwargs: CameraCfg | Mapping[str, Any] | None,
) -> MotrixCameraView:
camera = CameraCfg.from_kwargs(camera_kwargs)
if camera.cam_tracking:
if base_positions is None:
raise ValueError("base_positions is required when cam_tracking=true")
env_idx = max(0, min(camera.cam_tracking_env_idx, num_envs - 1))
tracking_camera = MotrixTrackingCamera(
env_idx=env_idx,
distance=camera.cam_distance,
elevation=camera.cam_elevation,
azimuth=camera.cam_azimuth,
)
lookat = tracking_camera_lookat(
base_positions,
tracking_camera,
np.asarray(offsets, dtype=np.float64),
)
return MotrixCameraView(
lookat=lookat,
distance=tracking_camera.distance,
elevation=tracking_camera.elevation,
azimuth=tracking_camera.azimuth,
tracking=tracking_camera,
)
if camera.cam_lookat is None:
offsets_np = np.asarray(offsets, dtype=np.float64)
lookat = [
float(np.mean(offsets_np[:, 0])),
float(np.mean(offsets_np[:, 1])),
0.75,
]
else:
lookat = [float(v) for v in camera.cam_lookat]
return MotrixCameraView(
lookat=lookat,
distance=camera.cam_distance,
elevation=camera.cam_elevation,
azimuth=camera.cam_azimuth,
)