Newer
Older
SmTIAS-LightSim / docs / 06_TEST / TEST_08_面光源スケール軸バグの発見と修正.md

面光源スケール軸バグの発見と修正 (Area-Light Scale-Axis Bug)

本ドキュメントは,実機の単灯(下/左/右)実測データとシミュレーションを 1 灯ずつ突き合わせた結果,シミュ側の面光源(area emitter)変換に座標軸の取り違えバグが見つかり,これが「下灯がほかの 2 倍強い」という長年の不一致の主因だったことの発見・原因・修正・検証を記録する.

⚠️ 本件により TEST_07 LED グループ別動作確認 の結論「下灯 2.1× は物理的に正しい/意図どおり」は誤りであったことが判明した(TEST_07 はバグ込みの出力を物理的に正当化してしまっていた).TEST_07 冒頭にも訂正注記を追加済み.

発端 — 実機単灯データとの突き合わせ

実機(SmTIAS-Evaluation)で 3 灯を 1 灯ずつ単独点灯して撮影した白板 ROI 輝度マップ一式を入力として受領した(lightsim/:luminance_maps/{bottom,left,right}_*.npy,0〜255 linear / Rec.709 luma / LSC 補正済 / portrait).

ユーザー観察:「シミュでは下側がほかの約 2 倍になっているが,実機では 3 灯ほぼ均等」.これを灯ごとに分解して原因を特定するのが目的.

灯ごとの白板 ROI 平均輝度(実機)と,既存シミュ単灯出力(output/led_group_sanity/,spp=1024)を比較:

灯実機 mean実機 比シミュ(バグ) meanシミュ(バグ) 比
bottom57.751.00(最暗)98.822.10
left61.461.0647.081.00
right63.551.1047.101.00

→ 実機は 3 灯ほぼ均等で下灯が最暗.シミュは下灯だけ 2.10×で,しかも左右が 47.08 vs 47.10 と完全対称.傾向が逆転している.

LED 定義(configs/leds_extracted.yaml)は全 18 灯が direction:(0,0,-1)・radiance:2807.25 で完全同一.LED の位置・向き・強度は Fusion 360 STL 由来で実機どおりであり,radiance 差では説明できない.したがって原因は LED 以外(周囲幾何・変換処理)にあると絞り込んだ.

原因 — 面光源スケールの軸取り違え

Mitsuba の rectangle 仕様(実機検証)

Mitsuba 3 の rectangle 形状を実際に生成して確認した:

中心法線 n = (0, 0, 1)        # 面は +Z を向く
面内範囲 = X∈[-1,1], Y∈[-1,1]  # XY 平面に寝た 1 辺 2 の正方形
Z 方向 = 厚みゼロ(潰れている)

→ rectangle は「XY 平面・法線 +Z」.サイズを与えるには 横 = X 軸,高さ = Y 軸をスケールしなければならない(Z は潰れているのでスケールしても無意味).

バグ箇所

src/sm_tias_lightsim/scene/lights.py _build_area_light_transform:

# 修正前(バグ)
scale = mi.ScalarTransform4f().scale([sw / 2.0, 1.0, sh / 2.0])
#                                       横X    縦Y     奥Z
#   横(X) = sw/2     … OK
#   縦(Y) = 1.0      … ★ スケールされず基準のまま = ±1 m(2000 mm)
#   奥(Z) = sh/2     … 高さを“潰れた厚み方向”に入れてしまい無効

コード上のコメントは「rectangle は XZ 平面上の正方形(Y 軸正方向が前面)」と書かれていたが,実体は XY 平面・+Z 前面.前提を 1 軸勘違いしたまま実装されており,高さ sh を縦(Y) ではなく奥行き(Z) に入れ,縦(Y) は無補正のまま放置されていた.

単位はメートル系(mm→m に position_scale=0.001 済)なので,縦が無補正 = ±1 m.結果:

実物 2.8 × 3.5 mm の小さな LED が,シミュ内では 「幅 ~3 mm × 高さ 2000 mm」の細長い巨大ストリップになっていた.

法線(発光方向)は look_at で正しく direction を向くため,発光の向き自体は正しい(このバグでは形状サイズだけが壊れる).

なぜ「下灯だけ 2 倍」になったか

全 18 灯が同一の look_at(direction=(0,0,-1), up=(0,1,0))を使うため local Y→world Y.つまり全 LED が world Y 方向に 2 m 伸びた縦ストリップになる.各灯列の横位置(X)と評価板の関係:

灯LED 横位置 X評価板 X 範囲 [-49.5, +49.5] との関係
bottomX∈[-10, +18]板中央の真裏(中央に密集)
leftX = -66板の外(左端より 16.5 mm 外側)+側壁/カバー脇
rightX = +66板の外(右端より 16.5 mm 外側)+側壁/カバー脇

2 m 縦長化により,板中央の真裏にある下灯だけが板中央を効率よく照らし,板の外側にある左右灯は伸びた光の多くが壁/カバーに当たって板に届きにくい.本来の小さな ~3.5 mm 面光源ならこの縦長効果は生じず偏らない.バグによる巨大化が,たまたま中央裏にある下灯を過剰に効かせて 2.1× を生んでいた.

TEST_07 はこの 2.1× を「直接光効率の幾何的優位=意図した設計」と解釈してしまったが,実際は変換バグによるアーティファクトだった.

修正

スケールの軸を 1 か所入れ替えるのみ:

# 修正後
scale = mi.ScalarTransform4f().scale([sw / 2.0, sh / 2.0, 1.0])
#                                       横X    縦Y     奥Z
#   横(X) = sw/2  縦(Y) = sh/2  奥(Z) = 1.0(潰れた厚みは無補正でよい)

高さ sh を,誤って入れていた奥行き(Z) から本来の縦(Y) へ移しただけ.これで LED が実物どおりの ~2.8 × 3.5 mm に戻る.

検証結果(spp=1024, max_depth=16 確定)

修正後に 3 単灯+全灯合成を再レンダ(単灯 output/sanity_fix_1024/,全灯 output/baseline_fix_1024/,いずれも spp=1024 / max_depth=16).暫定 spp=256 出力は output/led_group_sanity_fix/.

① 灯間バランス(mean 比,spp=1024)

灯バグ 比修正後 比実機 比
bottom2.0991.000(最暗)1.000(最暗)
left1.0001.0281.064
right1.0001.0261.100

→ 下灯 2 倍は消滅し,3 灯が ±3% で均等化.さらに**「下灯が最暗」という実機の順序まで一致**した.灯間の振幅バランスは実機パターンに乗った.

② 各灯の形(peak/mean,spp=1024)

灯バグ peak/mean修正後 peak/mean実機 peak/mean
bottom1.601.781.22
left1.781.691.27
right1.731.751.20
  • 絶対 mean は ~98/47 → ~4.5 へ低下:発光面積が 2.8mm×2000mm → 2.8mm×3.5mm へ約 570 倍縮小したため.絶対スケールは下流の露出ソルバ / mean anchor 正規化で吸収されるため灯間比・形が本質.
  • peak/mean はなお実機(1.2 台)に届かず(修正後 1.7 台)=各単灯フットプリントの拡散不足が残る(max_depth=8 の暫定では 2.9 と更に尖っていたが,depth=16 のバウンス増で 1.7 台まで滑らかになった).

③ 線形性(単灯和 ≈ 全灯)

単灯 3 本の和と全灯合成の ROI mean を比較:相対誤差 0.34%.Mitsuba の理論線形性どおりで,レンダの健全性を確認.

④ 全灯合成 CoV(公式 sm-evaluate, ROI image_pixel 464×450)

シーンlinear CoV対実機残差center/周辺比gradient
修正前(baseline_v3_leds,バグ)0.18152.61×1.31824.13
修正後(baseline_fix_1024)0.16412.36×1.31123.71
実機0.0695———

(参考:OETF/sRGB ドメインでは修正後 CoV=0.0790)

→ 合成 CoV は 0.1815→0.1641(残差 2.63×→2.36×)と小改善にとどまる.center/周辺比・勾配はほぼ不変.灯間バランスは直ったが,合成の主な不均一(中央明・縦勾配)は灯間バランスではなく各単灯フットプリントの拡散不足に由来するため,本バグ修正だけでは合成 CoV は大きく動かない(ユーザーの事前直感どおり).

学びと残課題

  1. 灯間の量的バランス問題は解決:下灯 2.1× は変換バグのアーティファクトであり,修正で実機どおり(3 灯均等・下灯最暗)になった.
  2. 論点が移動:残る不一致は「灯間バランス」ではなく各単灯フットプリントの拡散不足(peak/mean がシミュ 2.9 vs 実機 1.2).候補は LED 配光 ξ(指向の広がり)・ディフューザーのモデル化・面光源サイズの実測整合など.
  3. 最終目標(3 灯合成 CoV)への効果は小さい(確定):spp=1024 で合成 CoV は 0.1815→0.1641(残差 2.63×→2.36×)の小改善にとどまった.残差の主因は灯間バランスではなく各単灯フットプリントの拡散不足であり,本修正だけでは合成 CoV は大きく動かない.次の本筋は配光 ξ/ディフューザー拡散のモデル化.
  4. 過去の正当化に注意:TEST_07 のように「シミュ出力を物理で後付け説明」すると,変換バグを設計意図と取り違える危険がある.実機グラウンドトゥルースとの灯ごと突き合わせが有効だった.

関連ドキュメント