Newer
Older
SmTIAS-LightSim / src / sm_tias_lightsim / render / runner.py
# pyright: reportCallIssue=none
# Mitsuba 3 は variant ベースの動的属性解決を行うため Pylance/Pyright が
# mi.* を object 型と推論し reportCallIssue を誤検知する(GUIDE_06 の方針).
"""Mitsuba レンダリング実行モジュール.

variant 設定と mi.render() の実行を担う.
`mitsuba.set_variant` はこのモジュールで 1 度だけ呼ぶ.
"""

from __future__ import annotations

import logging
import shutil
from pathlib import Path

import mitsuba as mi
import numpy

from sm_tias_lightsim.scene.builder import build_scene
from sm_tias_lightsim.scene.schema import SceneConfig

_logger = logging.getLogger(__name__)

# 現在設定されている variant を追跡する(プロセス内 1 度だけ変更可能)
_current_variant: str | None = None


def render_scene(config: SceneConfig, project_root: Path | None = None) -> numpy.ndarray:
    """SceneConfig からシーンを構築してレンダリングし,HDR 画像(H, W, 3)を返す.

    Mitsuba の variant を config.render.variant に設定する(プロセス内初回のみ有効).
    既に異なる variant が設定されている場合は警告ログを出して続行する.

    Args:
        config: 検証済み SceneConfig.
        project_root: STL 相対パスの基点ディレクトリ.None なら CWD を使用.

    Returns:
        HDR 画像 (H, W, 3) の float32 配列.値域は物理量(0〜∞ も許容).
    """
    global _current_variant  # noqa: PLW0603

    desired_variant = config.render.variant

    if _current_variant is None:
        mi.set_variant(desired_variant)
        _current_variant = desired_variant
    elif _current_variant != desired_variant:
        _logger.warning(
            "Mitsuba variant is already set to %r; "
            "requested variant %r will be ignored. "
            "Restart the process to change the variant.",
            _current_variant,
            desired_variant,
        )
    # 同じ variant が既に設定されている場合は何もしない

    scene_dict, tempdir = build_scene(config, project_root=project_root)
    try:
        scene = mi.load_dict(scene_dict)
        image_tensor = mi.render(scene, spp=config.render.spp)
        arr = numpy.array(image_tensor)
    finally:
        shutil.rmtree(tempdir, ignore_errors=True)

    return arr