# pyright: reportCallIssue=none
# Mitsuba 3 は variant ベースの動的属性解決を行うため Pylance/Pyright が
# mi.* を object 型と推論し reportCallIssue を誤検知する(coding-style.md の方針).
# 処理本体(render_yaml)を main() 内で遅延 import しているのは,--help だけ使う場面
# (Mitsuba 不在の軽量環境)でも起動できるようにするためである.
# render/pipeline.py 自体も mitsuba 依存 import を関数内に閉じ込めており,
# llvm_* variant の DRJIT_LIBLLVM_PATH 設定が mitsuba import より前に走ることを保証する.
"""sm-render コマンドラインエントリポイント.
YAML シーン定義を読み込み,Mitsuba 3 でレンダリングを実行して
PNG と luminance.npy を出力ディレクトリに保存する.
処理本体は `render/pipeline.py` の `render_yaml()` にある(スイープ等から
プロセス内で直接呼べるようにするため).本モジュールは引数のパースと,
例外 → 「エラー: …」表示 + 終了コード 1 への変換だけを担う.
"""
from __future__ import annotations
import argparse
import sys
from pathlib import Path
def _parse_args(argv: list[str] | None = None) -> argparse.Namespace:
"""コマンドライン引数をパースして返す.
Args:
argv: 引数リスト.None のとき sys.argv[1:] を使用.
Returns:
パース済み Namespace.
"""
parser = argparse.ArgumentParser(
prog="sm-render",
description=(
"YAML シーン定義から Mitsuba 3 でレンダリングし PNG と luminance.npy を出力する."
),
)
parser.add_argument(
"--scene",
"-s",
required=True,
type=Path,
metavar="YAML_PATH",
help="シーン定義 YAML ファイルのパス.",
)
parser.add_argument(
"--output",
"-o",
required=True,
type=Path,
metavar="OUTPUT_DIR",
help="出力先ディレクトリ(存在しない場合は親ごと作成する).",
)
parser.add_argument(
"--variant",
default=None,
metavar="VARIANT",
help=(
"Mitsuba variant を上書きする(例: cuda_ad_rgb)."
"未指定なら環境変数 SM_RENDER_VARIANT,それも無ければ YAML の render.variant を使う."
),
)
return parser.parse_args(argv)
def main(argv: list[str] | None = None) -> int:
"""sm-render コマンドのメインエントリポイント.
引数をパースして `render_yaml()` を呼び,段階別のエラーを終了コードに変換する.
レンダそのものの処理フローは `render/pipeline.py` の `render_yaml()` を参照.
Args:
argv: 引数リスト.None のとき sys.argv[1:] を使用.
Returns:
終了コード(成功時 0,失敗時 1).
"""
# argparse 自体のエラー(必須引数欠落等)は ArgumentParser が直接 sys.exit するため
# ここでは ValueError / FileNotFoundError 等の実行時エラーのみ捕捉する
args = _parse_args(argv)
# mitsuba 依存のモジュールを読み込む前に引数をパースする(--help を軽量に保つ)
from sm_tias_lightsim.render.pipeline import RenderStepError, render_yaml
try:
png_path, npy_path = render_yaml(
args.scene.resolve(),
args.output.resolve(),
args.variant,
)
except RenderStepError as exc:
print(f"エラー: {exc}", file=sys.stderr)
return 1
print(f"レンダリング完了: {png_path}")
print(f"輝度マップ保存: {npy_path}")
return 0