Newer
Older
SmTIAS-LightSim / src / sm_tias_lightsim / scene / materials.py
"""YAML 材料定義 → Mitsuba BSDF dict 変換モジュール."""

from __future__ import annotations

from sm_tias_lightsim.scene.schema import (
    DielectricMaterial,
    DiffuseMaterial,
    MaterialConfig,
    ThinDielectricMaterial,
)


def _to_rgb(value: float | tuple[float, float, float]) -> list[float]:
    """スカラまたは RGB タプルを 3 要素の float リストに正規化する.

    lights.py / materials.py 共通のヘルパ.このモジュールが正本で,
    lights.py はここから import して重複を回避する.

    Args:
        value: スカラ(全チャンネル同値)または RGB タプル.

    Returns:
        3 要素の float リスト.
    """
    if isinstance(value, (int, float)):
        return [float(value)] * 3
    return list(value)


def build_material_dict(material: MaterialConfig) -> dict:
    """1 MaterialConfig を Mitsuba BSDF dict に変換する.

    Args:
        material: SceneConfig.materials の値(DiffuseMaterial 等).

    Returns:
        Mitsuba BSDF dict.
        - diffuse → {"type": "diffuse", "reflectance": {"type":"rgb","value":[r,g,b]}}
        - dielectric → {"type": "dielectric", "int_ior": ..., "ext_ior": ...}
        - thindielectric → {"type": "thindielectric", "int_ior": ..., "ext_ior": ...}

    Raises:
        ValueError: 未対応の材料タイプが指定された場合.
    """
    if isinstance(material, DiffuseMaterial):
        return {
            "type": "diffuse",
            "reflectance": {
                "type": "rgb",
                "value": _to_rgb(material.reflectance),
            },
        }

    if isinstance(material, DielectricMaterial):
        return {
            "type": "dielectric",
            "int_ior": material.int_ior,
            "ext_ior": material.ext_ior,
        }

    if isinstance(material, ThinDielectricMaterial):
        return {
            "type": "thindielectric",
            "int_ior": material.int_ior,
            "ext_ior": material.ext_ior,
        }

    msg = f"Unsupported material type: {type(material).__name__}"
    raise ValueError(msg)