Skip to content

Add Material.to_threejs() and Material.to_gltf() output adapters #35

@gerchowl

Description

@gerchowl

NOTE: The original body below is superseded by the
final API comment.
Key change: PBR scalars STAY in .properties.pbr, adapters
take Material (not Vis), .vis owns textures + source
reference only.

API design (final, see comment for authoritative version)

Namespace

  • .properties.pbr — PBR scalars from TOML (roughness, metallic, ior). Always available.
  • .vis — mat-vis remote data (textures, source_id, fetch). Lazy, nullable.
  • Adapters — standalone functions in pymat.vis.adapters:
    to_threejs(material), to_gltf(material), export_mtlx(material, path).
    Signature takes Material, reads from both .properties.pbr and .vis.
  • Shim — pymat.vis.shim fully exposed.

Field name mapping

Canonical mapping between ecosystems:

Concept py-mat mat-vis (index/rowmap/parquet) Three.js glTF
Metal scalar metallic metalness metalness metallicFactor
Roughness scalar roughness roughness roughness roughnessFactor
Base color base_color (RGBA tuple) color_hex (#RRGGBB) color (hex int) baseColorFactor
Color texture color (channel) map baseColorTexture
Normal texture normal (channel) normalMap normalTexture
Roughness texture roughness (channel) roughnessMap (packed in metallicRoughnessTexture)
Metalness texture metalness (channel) metalnessMap (packed in metallicRoughnessTexture)
AO texture ao (channel) aoMap occlusionTexture

Each adapter hardcodes its own translation using this table.
py-mat keeps metallic (established API, matches glTF's root term).
mat-vis keeps metalness (matches Three.js and upstream source naming).

Material → vis source_id mapping

A vis_source_id field in the TOML data files links a py-mat
material to its mat-vis appearance:

[stainless.s316L]
name = "Stainless Steel 316L"
vis_source_id = "ambientcg/Metal_Brushed_001"

Nullable — materials without a mat-vis appearance simply have
vis = None. Curated manually as mat-vis publishes data.

resolve() semantics

vis.resolve(channel, pbr) returns a ResolvedChannel:

@dataclass
class ResolvedChannel:
    texture: bytes | None    # PNG bytes if texture exists
    scalar: float | None     # scalar fallback
    has_texture: bool

Adapters use this to decide: texture map or uniform value.

Acceptance

  • Vis class with source_id, tier, textures dict, resolve()
  • vis_source_id field in Material + TOML schema
  • Field name mapping table in a shared constants module
  • pymat.vis.shim — get_manifest, fetch, rowmap_entry
  • pymat.vis.adapters — to_threejs, to_gltf, export_mtlx
    (signature: takes Material, reads both namespaces)
  • Tests for Vis, shim, resolve, each adapter
  • Coordinate with @bernhard-42 on ocp_vscode

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions