Skip to content

[MAX-MAT-002] Strip buggy emission=1.0 / emission_color=(0,0,0) from MaterialX export#37

Open
doug-smith-miris wants to merge 2 commits into
Autodesk:devfrom
doug-smith-miris:miris/max-mat-002-strip-buggy-emission-default
Open

[MAX-MAT-002] Strip buggy emission=1.0 / emission_color=(0,0,0) from MaterialX export#37
doug-smith-miris wants to merge 2 commits into
Autodesk:devfrom
doug-smith-miris:miris/max-mat-002-strip-buggy-emission-default

Conversation

@doug-smith-miris

Copy link
Copy Markdown

Summary

Stacked on top of #36 (MAX-MAT-001). Until that PR merges, this PR's diff includes its commits too — once MAX-MAT-001 merges into dev, this PR's diff will collapse to just the MAX-MAT-002 changes (1 commit, 4 files).

Adds a second post-parse normalization pass in MtlxShaderWriter::Write() that strips the spurious emission = 1.0 paired with emission_color = (0, 0, 0) that 3ds Max's MtlxIOUtil bridge writes on every ND_standard_surface_surfaceshader.

The MaterialX standard_surface nodedef defaults are emission = 0.0 and emission_color = (1, 1, 1). The buggy pair multiplies to (0, 0, 0) so it has no visual effect, but it is semantically wrong:

  • A downstream override that bumps emission_color away from black inherits a full-strength emission = 1.0 the artist never asked for.
  • A round-trip importer reads emission_color = (0, 0, 0) as "explicit black emission" rather than "no emission authored" — semantically different states that diverge under later edits.
  • The values do not match the source DCC: PhysicalMaterial has no emission knob set to 1.0, and never asked for an emission color of pure black.

What changed

  • src/translators/MtlxShaderWriter.cpp:
    • Adds _TryGetStaticColor3 — parses MaterialX color3 value strings ("r, g, b" or "r g b") when not connected; rejects strings with the wrong component count.
    • Adds _NormalizeStandardSurfaceEmissionDefault — walks standard_surface nodes and strips both emission and emission_color inputs when both are statically the buggy pair. Any deviation (connected input, non-1.0 emission, non-black color, missing half) leaves both untouched.
    • Invokes the new pass in Write() immediately after _NormalizeStandardSurfaceSpecularRotation.
  • doc/translation-mapping.md: adds a new row + section + change log entry.
  • doc/changelog.md: adds an Unreleased fix entry.
  • src/Tests/Integration/mtlxShaderWriter_test.ms: adds test_export_physical_material_strips_buggy_emission_default.

Validation

3ds Max is Windows-only and this repo builds via Visual Studio; build/run was deferred (same constraint as #36). A Python validator that mirrors the C++ logic 1:1 at the USD layer was run on the diagnostic corpus and synthetic fixtures.

Diagnostic corpus (complex_export_mat001_postfix.usda, MAX-MAT-001-clean): 6/6 standard_surface shaders affected. The USDA diff is exactly 12 deletions (6 emission, 6 emission_color), zero additions, zero structural changes.

Karma renders of pre-fix and post-fix corpora are byte-identical (SHA-256 eaf38328...). This is the expected outcome and the success signal — the buggy pair multiplies to zero emission, the nodedef-default pair multiplies to zero emission, both produce the same BSDF lighting result.

Synthetic negative-test fixture (_synthetic_with_emission.usda):

  • BrushedSteel emission_color set to (0.8, 0.4, 0.1) — intentional orange emission tint → kept.
  • Copper emission set to 0.5 — intentional partial emission → kept.
  • The 4 untouched buggy materials → stripped.

The MaxScript regression test extends the existing PhysicalMaterial test pattern from MAX-MAT-001.

Reference files (validator + corpus)

Under agent/arch-builds/f72c97e6-301f-400a-9e77-c768979e8fa5/ (outside the repo):

  • normalize_emission_default.py — USD-layer mirror of the C++ logic.
  • complex_export_mat001_postfix.usda — input (MAX-MAT-001-clean, MAX-MAT-002-dirty).
  • complex_export_postfix.usda — output (MAX-MAT-001+002-clean).
  • make_negative_fixture.py, _synthetic_with_emission.usda, _synthetic_postfix.usda.
  • render_karma_prefix.png, render_karma_postfix.png (byte-identical), compare_side_by_side.png.
  • intended_example.md — detailed observable / fixture description for the auditor.

Test plan

  • Reviewer confirms the C++ pattern mirrors MAX-MAT-001 conservatively.
  • On a Windows 3ds Max install, run the MaterialX export integration suite (mtlxShaderWriter_test.ms) and confirm the new test passes alongside the MAX-MAT-001 test.
  • On a Windows 3ds Max install, export a fresh complex scene via the plugin and confirm no emission = 1.0 + emission_color = (0, 0, 0) pair appears on any standard_surface shader, while any intentionally authored emission is preserved.

🤖 Generated with Claude Code

Doug Smith and others added 2 commits June 20, 2026 17:43
3ds Max's MtlxIOUtil bridge hardcodes specular_rotation=0.25 on every
ND_standard_surface_surfaceshader, regardless of source PhysicalMaterial
anisotropy. The MaterialX nodedef default is 0.0; the value has no
visual effect when specular_anisotropy is zero (the BSDF multiplies
them), but it silently introduces a 90deg highlight rotation if a
downstream layer turns anisotropy on.

Add a post-parse normalization pass in MtlxShaderWriter::Write that
walks the parsed MaterialX document and drops specular_rotation from
standard_surface nodes when:
  * the value is statically 0.25 (the bug pattern), AND
  * specular_anisotropy is absent or statically 0.0.

Connected anisotropy, any non-0.25 rotation value, and connected
rotation are conservatively left untouched.

Validated against the diagnostic corpus (samples/complex_export.usda):
6/6 affected materials cleaned, Karma renders byte-identical pre/post
(SHA-256 match — semantic-only fix). Synthetic negative test
(BrushedSteel with specular_anisotropy=0.4) confirms the fix is
surgical and preserves intentional rotation.

Also adds doc/translation-mapping.md to track 3ds Max -> MaterialX
property mappings going forward, and a MaxScript regression test in
mtlxShaderWriter_test.ms.

Build/run validation deferred: 3ds Max is Windows-only and this repo
builds via Visual Studio (configure-vsdevcmd.bat). The Python
validator in the arch-build dir mirrors the C++ logic exactly at the
USD layer.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3ds Max's MtlxIOUtil bridge hardcodes emission=1.0 paired with
emission_color=(0,0,0) on every ND_standard_surface_surfaceshader,
regardless of the source PhysicalMaterial. The MaterialX nodedef defaults
are emission=0.0 and emission_color=(1,1,1); the buggy pair multiplies to
(0,0,0) so it has no visual effect, but it is semantically wrong --
any downstream layer that bumps emission_color away from black would
unexpectedly turn emission on at full strength, and any round-trip
importer reads (0,0,0) as "explicit black emission" rather than "no
emission authored".

Add a second post-parse normalization pass in MtlxShaderWriter::Write
(immediately after MAX-MAT-001's pass) that walks the parsed MaterialX
document and strips BOTH inputs from standard_surface nodes when:
  * emission is statically 1.0 (no connection, tolerant of float noise),
  * emission_color is statically (0,0,0) (no connection, same tolerance),
  * AND both inputs are present (the bug is the pair; treating either
    half in isolation could destroy a real authored value).

Any deviation -- non-1.0 emission, non-black color, connected input,
missing half -- leaves both inputs untouched.

Adds a small _TryGetStaticColor3 helper that parses MaterialX color3
value strings ("r, g, b" or "r g b") via istringstream with separator
normalization; rejects strings with the wrong number of components.

Validated against the diagnostic corpus (samples/complex_export.usda)
via a Python validator that mirrors the C++ logic 1:1 at the USD layer:
6/6 affected materials cleaned, exactly 12 deletions in the USDA diff
(6 emission + 6 emission_color), zero additions, zero structural
changes. Karma renders byte-identical pre/post (SHA-256 match -- the
buggy pair multiplies to zero emission, the nodedef defaults also
multiply to zero emission, both produce the same BSDF lighting result).

Synthetic negative-test fixture (BrushedSteel with intentional
emission_color=(0.8, 0.4, 0.1); Copper with intentional emission=0.5)
confirms the fix is surgical: 4/6 stripped, both intentional materials
preserved.

Also updates doc/translation-mapping.md and adds a MaxScript
regression test in mtlxShaderWriter_test.ms.

Build/run validation deferred: 3ds Max is Windows-only and this repo
builds via Visual Studio. The Python validator mirrors the C++ logic
exactly at the USD layer.

Stacked on top of Autodesk#36 (MAX-MAT-001).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant