# pyright: reportCallIssue=none
# Mitsuba 3 は variant ベースの動的属性解決を行うため Pylance/Pyright が
# mi.* を object 型と推論し reportCallIssue を誤検知する(coding-style.md の方針).
"""YAML センサ定義 → Mitsuba sensor dict 変換モジュール."""
from __future__ import annotations
import mitsuba as mi
from sm_tias_lightsim.scene.schema import SensorConfig
def build_sensor_dict(sensor: SensorConfig, position_scale: float) -> dict:
"""SensorConfig を Mitsuba sensor dict に変換する.
Args:
sensor: SceneConfig.sensor.
position_scale: 座標スケール係数(mm→m なら 0.001).position/target にも適用.
Returns:
Mitsuba sensor dict(perspective または orthographic).
"""
pos = [c * position_scale for c in sensor.position]
target = [c * position_scale for c in sensor.target]
up = list(sensor.up)
film = {
"type": "hdrfilm",
"width": sensor.film.width,
"height": sensor.film.height,
"rfilter": {"type": sensor.film.rfilter},
}
sampler = {"type": "independent", "sample_count": 1}
if sensor.type == "perspective":
to_world = mi.ScalarTransform4f().look_at(origin=pos, target=target, up=up)
return {
"type": "perspective",
"fov": sensor.fov_deg,
"to_world": to_world,
"film": film,
"sampler": sampler,
}
# orthographic: ortho_scale (mm) を画像幅・高さの半幅として使う.
# Mitsuba の orthographic は clip-space X,Y が ±1 → look_at × scale で実空間範囲を決める.
if sensor.ortho_scale is None:
msg = "orthographic sensor requires ortho_scale (validated in schema)"
raise RuntimeError(msg)
sx_m = sensor.ortho_scale[0] * position_scale
sy_m = sensor.ortho_scale[1] * position_scale
to_world = (
mi.ScalarTransform4f().look_at(origin=pos, target=target, up=up)
# Z 方向はスケールしない(奥行き軸はそのまま look_at の視錐台に従う)
@ mi.ScalarTransform4f().scale([sx_m, sy_m, 1.0])
)
return {
"type": "orthographic",
"to_world": to_world,
"film": film,
"sampler": sampler,
}