diff --git a/CLAUDE.md b/CLAUDE.md index d1b25d0..27f04d7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -5,10 +5,11 @@ ## 開発進捗 -現在の進捗: GUIDE_01 フェーズ 4(仕様設計)— `SPEC_01_*.md` 作成中 +現在の進捗: GUIDE_01 フェーズ 5(規約整備)— `GUIDE_06〜09` 作成中 ※ フェーズ 1(方針決定)完了: [docs/03_PLAN/PLAN_01_要件定義書.md](docs/03_PLAN/PLAN_01_要件定義書.md) ※ フェーズ 2(技術選定)完了: [docs/02_ENV/ENV_01_技術スタック.md](docs/02_ENV/ENV_01_技術スタック.md) ※ フェーズ 3(環境構築)完了: [docs/02_ENV/ENV_02_環境構築手順.md](docs/02_ENV/ENV_02_環境構築手順.md), [docs/02_ENV/ENV_03_管理者用環境構築手順.md](docs/02_ENV/ENV_03_管理者用環境構築手順.md) +※ フェーズ 4(仕様設計)完了: [docs/04_SPEC/SPEC_01_アーキテクチャ設計.md](docs/04_SPEC/SPEC_01_アーキテクチャ設計.md), [docs/04_SPEC/SPEC_02_シーン定義仕様.md](docs/04_SPEC/SPEC_02_シーン定義仕様.md) ※ ステップ完了時にここを更新すること. ## 必須ルール(コード実装時) diff --git "a/docs/04_SPEC/SPEC_01_\343\202\242\343\203\274\343\202\255\343\203\206\343\202\257\343\203\201\343\203\243\350\250\255\350\250\210.md" "b/docs/04_SPEC/SPEC_01_\343\202\242\343\203\274\343\202\255\343\203\206\343\202\257\343\203\201\343\203\243\350\250\255\350\250\210.md" new file mode 100644 index 0000000..e3d4b21 --- /dev/null +++ "b/docs/04_SPEC/SPEC_01_\343\202\242\343\203\274\343\202\255\343\203\206\343\202\257\343\203\201\343\203\243\350\250\255\350\250\210.md" @@ -0,0 +1,158 @@ +# アーキテクチャ設計 (Architecture) + +## 概要 (Overview) + +SmTIAS-LightSim は次の 2 段階を独立した CLI として提供する. + +1. **render**: シーン定義 YAML + STL メッシュを入力に,Mitsuba 3 で擬似撮影画像(PNG)と輝度マップを出力する. +2. **evaluate**: PNG または輝度マップ + ROI 設定を入力に,MiniTias-Evaluation 互換の均一性指標(CSV)と可視化(PNG)を出力する. + +evaluate を独立させることで,**実測 PNG(MiniTIAS で撮影したもの)にも同じコマンドが使える**.シミュレーションと実測を同じ物差しで比較できる. + +## 全体パイプライン (Pipeline) + +``` + [Fusion 360] + ↓ STL export + ┌─────────────────────────────────────────────────────────────┐ + │ configs/ │ + │ ├── scene_baseline.yaml (光源・材料・センサ・評価面定義) │ + │ └── meshes/ │ + │ └── *.stl │ + └─────────────────────────────────────────────────────────────┘ + ↓ + ┌─────────────── render ──────────────┐ + │ scene/builder → Mitsuba scene │ + │ render/runner → mi.render(...) │ + │ render/output → PNG / luminance │ + └──────────────────────────────────────┘ + ↓ + output// + ├── render.png + └── luminance.npy + ↓ + ┌─────────────── evaluate ────────────┐ + │ evaluation/roi → ROI抽出 │ + │ uniformity.py → CoV / std │ + │ evaluation/zones → 3ゾーン │ + │ evaluation/radial → 放射プロファ │ + │ evaluation/visualize → 可視化PNG │ + └──────────────────────────────────────┘ + ↓ + output// + ├── metrics.csv + └── figures/ + ├── luminance_map.png + ├── histogram.png + ├── radial_profile.png + └── zone_map.png +``` + +## モジュール構成 (Modules) + +``` +src/sm_tias_lightsim/ +├── __init__.py +├── geometry/ +│ ├── loader.py # trimesh で STL 読込・三角形配列取得 +│ └── transforms.py # 単位変換 (mm→m)・座標系変換 +├── scene/ +│ ├── schema.py # YAML スキーマ定義・バリデーション +│ ├── builder.py # YAML → Mitsuba scene dict 変換の本体 +│ ├── lights.py # LED 光源 (point / area / spot) のシーン要素生成 +│ ├── materials.py # BSDF(拡散・誘電体・薄膜散乱等)の生成 +│ └── sensors.py # カメラセンサ (perspective / orthographic) の生成 +├── render/ +│ ├── runner.py # mi.set_variant + mi.render の実行 +│ └── output.py # HDR film → PNG / luminance.npy 出力 +├── uniformity.py # MiniTias-Evaluation からコピー(Rec.709, CoV, max/min) +├── evaluation/ +│ ├── roi.py # 画像 ROI 抽出(image_pixel / scene_face) +│ ├── zones.py # 3 ゾーン分析(center / middle / periphery) +│ ├── radial.py # 放射状プロファイル生成 +│ └── visualize.py # matplotlib による可視化 PNG 出力 +└── cli/ + ├── render.py # `sm-render` エントリポイント + └── evaluate.py # `sm-evaluate` エントリポイント +``` + +## 各層の責務 (Module Responsibilities) + +| 層 | 責務 | 主要な型・出入力 | +| --- | --- | --- | +| `geometry` | STL を読み,Mitsuba が扱える単位・座標系に揃える.メッシュの妥当性チェック | 入力: STL ファイルパス.出力: 頂点・面配列 + 単位情報 | +| `scene/builder` | YAML 設定全体を Mitsuba scene dict に変換するエントリ.他のサブ層を呼ぶ | 入力: YAML dict.出力: Mitsuba scene | +| `scene/lights` | YAML 光源定義 → Mitsuba の `point` / `area` / etc. emitter | 1 LED 定義 → 1 emitter | +| `scene/materials` | YAML 材料定義 → Mitsuba BSDF(`diffuse` / `dielectric` / `thindielectric`) | 1 材料定義 → 1 BSDF | +| `scene/sensors` | YAML センサ定義 → Mitsuba `perspective` センサ | 1 センサ定義 → 1 sensor | +| `render/runner` | Mitsuba scene + パラメータ → 輝度配列 | spp / max_depth / variant 切替 | +| `render/output` | 輝度配列 → PNG / luminance.npy ファイル | tone mapping 等の選択肢を持つ | +| `evaluation/roi` | 画像 + ROI 定義 → ROI 内の輝度配列 | image_pixel / scene_face 両対応 | +| `uniformity` | 輝度配列 → 均一性指標 dict | MiniTias-Evaluation 仕様準拠 | +| `evaluation/zones` | 輝度配列 → 中心 / 中間 / 周辺の各統計 | 距離正規化を内部で行う | +| `evaluation/radial` | 輝度配列 → 中心からの距離 vs 平均輝度 | プロット用データ | +| `evaluation/visualize` | 各種統計 → matplotlib 図 PNG | 可視化のみ.データ加工はしない | +| `cli/render`, `cli/evaluate` | 各ステップの CLI ラッパー | 引数パース・ファイル I/O | + +## エントリポイント (CLI Entry Points) + +`pyproject.toml` の `[project.scripts]` に登録する: + +```toml +[project.scripts] +sm-render = "sm_tias_lightsim.cli.render:main" +sm-evaluate = "sm_tias_lightsim.cli.evaluate:main" +``` + +使い方: + +```powershell +# シミュ実行 +uv run sm-render --scene configs/scene_baseline.yaml --output output/baseline/ + +# 評価(シミュ画像) +uv run sm-evaluate --image output/baseline/render.png --config configs/eval_default.yaml --output output/baseline/ + +# 評価(実測画像) +uv run sm-evaluate --image data/whiteboard_real.png --config configs/eval_default.yaml --output output/real/ +``` + +## ディレクトリ構成(プロジェクトルート) + +``` +SmTIAS-LightSim/ +├── src/sm_tias_lightsim/ # 上述 +├── configs/ +│ ├── scene_baseline.yaml +│ ├── eval_default.yaml +│ └── meshes/ # STL ファイル群 +├── output/ # シミュ・評価結果(.gitignore 対象) +├── tests/ +│ ├── test_geometry.py +│ ├── test_scene_builder.py +│ ├── test_uniformity.py +│ └── fixtures/ +└── docs/ +``` + +## キャリブレーション戦略 (Calibration) + +実測値(CoV ≈ 0.0426,勾配 ≈ 6%)との一致を確認するための運用: + +1. 現行 MiniTIAS の構成を `scene_baseline.yaml` に再現 +2. `sm-render → sm-evaluate` で指標を算出 +3. 実測値と比較し,差分が大きい場合は次の順で疑う: + - ① 光源の配光(Lambertian / cosine 分布の前提が妥当か) + - ② 材料パラメータ(拡散反射率・透過散乱) + - ③ ジオメトリの単位・座標 + - ④ サンプル数(spp)が不足していないか +4. 一致した時点でキャリブレーション完了.以降の改良案はこのベースラインからの相対比較で評価 + +許容範囲の数値は基準設計のレンダリング結果を見て確定する(`PLAN_02_開発ステップ.md` 内で定義). + +## 既知の前提 (Assumptions) + +- 入力 STL は閉じたメッシュ(モンテカルロ光線が漏れない)であること +- 単位は YAML 側で明示する(`unit: mm`).Fusion 360 の既定 mm 出力を想定 +- LED の配光は当初 Lambertian で仮置きし,必要に応じて IES データに置換可能な構造にしておく +- 色再現性は将来課題(要件定義書のスコープ外) diff --git "a/docs/04_SPEC/SPEC_02_\343\202\267\343\203\274\343\203\263\345\256\232\347\276\251\344\273\225\346\247\230.md" "b/docs/04_SPEC/SPEC_02_\343\202\267\343\203\274\343\203\263\345\256\232\347\276\251\344\273\225\346\247\230.md" new file mode 100644 index 0000000..f8927dc --- /dev/null +++ "b/docs/04_SPEC/SPEC_02_\343\202\267\343\203\274\343\203\263\345\256\232\347\276\251\344\273\225\346\247\230.md" @@ -0,0 +1,163 @@ +# シーン定義仕様 (Scene Definition Schema) + +## 概要 (Overview) + +シミュレーション 1 回分の入力を 1 つの YAML ファイルにまとめる.光源・材料・ジオメトリ・センサ・評価面・レンダ設定を含む.`scene/builder` がこの YAML を Mitsuba 3 の scene dict に変換する. + +## トップレベル構造 (Top-level Schema) + +```yaml +name: # 必須.設計識別名(出力ディレクトリ名に使う) +description: # 任意.自由記述 + +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 + +```yaml +sensor: + type: perspective # perspective のみ対応 + position: [0, 0, 50] # mm + target: [0, 0, 0] + up: [0, 1, 0] + fov_deg: 60 # x 方向 FOV + film: + width: 1920 + height: 1920 + rfilter: gaussian # ピクセルフィルタ +``` + +### 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 +``` + +省略した場合は `sm-evaluate` の `--config` で別ファイルを指定する. + +## バリデーション + +`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 つから複数バリアント生成) +- マルチセンサ対応