# シーン定義仕様 (Scene Definition Schema)

## 概要 (Overview)

シミュレーション 1 回分の入力を 1 つの YAML ファイルにまとめる．光源・材料・ジオメトリ・センサ・評価面・レンダ設定を含む．`scene/builder` がこの YAML を Mitsuba 3 の scene dict に変換する．

## トップレベル構造 (Top-level Schema)

```yaml
name: <string>            # 必須．設計識別名（出力ディレクトリ名に使う）
description: <string>     # 任意．自由記述

geometry: { ... }         # 必須．メッシュ一覧
materials: { ... }        # 必須．名前付き BSDF 辞書
lights: [ ... ]           # 必須．光源リスト（1 個以上）
sensor: { ... }           # 必須．カメラ 1 個（複数センサは未対応）
render: { ... }           # 必須．レンダリングパラメータ
evaluation: { ... }       # 任意．評価設定（省略時は CLI で別 YAML 指定）
```

## 各セクション

### geometry

```yaml
geometry:
  meshes:
    - id: housing                     # シーン内ユニーク ID
      path: configs/meshes/housing.stl
      unit: mm                        # mm | m
      material: housing_inner         # materials の key を参照
    - id: diffuser
      path: configs/meshes/diffuser.stl
      unit: mm
      material: diffuser_pmma
    - id: whiteboard
      path: configs/meshes/whiteboard.stl
      unit: mm
      material: white_lambert
```

- `path` はプロジェクトルートからの相対パス
- 同一 STL を異なる材料で複数回参照したい場合は `id` を変えて別エントリにする

### materials

```yaml
materials:
  housing_inner:
    type: diffuse
    reflectance: [0.05, 0.05, 0.05]   # マットな筐体内壁

  white_lambert:
    type: diffuse
    reflectance: 0.95                 # スカラ可．RGB 同値の近似白

  diffuser_pmma:
    type: thindielectric              # 薄膜誘電体（半透明散乱の簡易モデル）
    int_ior: 1.49                     # PMMA 屈折率
    ext_ior: 1.0
```

サポート予定の `type`：

| type | Mitsuba 対応 BSDF | 用途 |
| --- | --- | --- |
| `diffuse` | `diffuse` | Lambertian 反射 |
| `dielectric` | `dielectric` | 誘電体（厚みあり） |
| `thindielectric` | `thindielectric` | 薄膜誘電体（ディフューザー薄板） |
| `mask` | `mask` | 透過率マスク |
| 拡張余地 | `roughconductor` 等 | 反射率調整 |

### lights

```yaml
lights:
  - id: led_top
    type: point                      # point | area | directional
    position: [0, 30, 10]            # mm 単位
    intensity: [1.0, 1.0, 1.0]       # RGB．スカラも可
    profile: lambertian              # lambertian | isotropic | ies

  - id: led_ring_segment
    type: area
    shape: rectangle
    center: [0, 0, 20]
    size: [10, 10]                   # mm
    direction: [0, 0, -1]
    radiance: [50, 50, 50]
```

`profile: ies` のときは別途 `.ies` ファイルパスを指定する（将来拡張）．

### sensor

`type` は `perspective`（通常カメラ）または `orthographic`（平行投影）から選ぶ．

```yaml
# パターン 1: perspective（通常カメラ）— fov_deg 必須
sensor:
  type: perspective
  position: [0, 0, 50]               # mm
  target: [0, 0, 0]
  up: [0, 1, 0]
  fov_deg: 60                        # x 方向 FOV [deg]
  film:
    width: 1920
    height: 1920
    rfilter: gaussian                # ピクセルフィルタ

# パターン 2: orthographic（平行投影）— ortho_scale 必須
sensor:
  type: orthographic
  position: [0, 0, -50]              # mm（撮影面に対する距離）
  target: [0, 0, 0]                  # 撮影面の中心
  up: [0, 1, 0]
  ortho_scale: [50, 52]              # 撮影範囲の半幅 (sx, sy) [mm]．画像 X 軸 ±sx, Y 軸 ±sy にマップ
  film:
    width: 512
    height: 512
    rfilter: gaussian
```

`orthographic` は **評価板の表面上の照度マップを 2D 画像として直接取得** する用途で使う．
pixel と評価板の物理 mm 座標が 1 対 1 で対応し、パースペクティブ歪みがない．
詳細は [SPEC_03_基準設計の物理構成](SPEC_03_基準設計の物理構成.md) のカメラ（センサ）セクションを参照．

### render

```yaml
render:
  variant: llvm_ad_rgb               # 省略時は llvm_ad_rgb
  integrator: path                   # path | direct | volpath
  max_depth: 8
  spp: 256                           # サンプル数
```

### evaluation（任意）

```yaml
evaluation:
  roi:
    type: image_pixel                # image_pixel | scene_face
    x: 539
    y: 1015
    width: 1400
    height: 1409
  zones:
    enabled: true
    boundaries: [0.33, 0.66]         # 中心d<0.33 / 中間 / 周辺d≥0.66
  metrics:
    cov: true
    std: true
    max_min: true
    radial_profile: true
  oetf:                              # 任意．省略時 OETF 無効（linear のまま評価＝後方互換）
    enabled: true                    # シミュ linear 出力を実測と同じ sRGB 空間へ変換
    transfer: srgb                   # srgb のみ（IEC 61966-2-1）
    exposure:
      mode: anchor_mean              # OETF 後 ROI mean を target_mean に対数二分で合わせる（実測 AE アンカー）
      target_mean: 146.7146          # 実測 ROI mean（uint8 [0,255] スケール）
    quantize_uint8: true             # OETF 後を実測 PNG 同様 uint8 量子化
```

省略した場合は `sm-evaluate` の `--config` で別ファイルを指定する．

#### oetf（任意・後方互換）

シミュは linear radiance、実測 PNG は ISP の sRGB ガンマ符号化値であり、無次元指標（CoV/勾配/比）は非線形変換下で不変でないため、**シミュ vs 実測の数値突合には OETF 順方向適用が必須**（詳細は [SPEC_03「キャリブレーション経過」](SPEC_03_基準設計の物理構成.md)）．`oetf.enabled=true` のとき `sm-evaluate` は ROI 抽出後・指標算出前に標準 sRGB OETF を適用する．露出は AE が制御する量＝実測 ROI mean にアンカー（線形ゲインなので形状指標に自由度を持ち込まない）．`oetf` キー省略時は `enabled=False` 扱いで従来どおり linear 評価．

**重要（非対称性）**: OETF はシミュ出力にのみ適用する．実測 PNG は既に sRGB 符号化済みのため、実測用評価設定（`configs/eval_real.yaml` 等）には `oetf` を**付けない**（二重適用は誤り）．

## バリデーション

`scene/schema.py` で以下をチェック（Pydantic 想定）：

- 必須キー欠落
- ID の重複
- 参照整合性（meshes が存在しない materials を参照していないか）
- 単位指定の妥当性
- センサ FOV / 解像度の現実性（極端値の警告）

## 設計の意図

- **テキスト 1 ファイルで 1 設計**：履歴管理（git diff）で設計変更が見える
- **YAML を表面に，Mitsuba XML を裏に**：Mitsuba の柔軟性を保ちつつ，編集面では構造化された読みやすさを優先
- **mm を既定**：Fusion 360 と一致させ，変換ミスを防ぐ
- **評価設定をシーンと同居も別出しも可**：シーン固定で評価条件だけ振りたい場合に便利

## 将来拡張

- スペクトル光源（`llvm_ad_spectral` 用）の RGB → スペクトル変換層
- IES 配光ファイル対応
- パラメータスイープ（YAML 1 つから複数バリアント生成）
- マルチセンサ対応
