Skip to content

Align MaterialX to ASWF Color Interop Forum recommendation - #3042

Merged
jstone-lucasfilm merged 7 commits into
AcademySoftwareFoundation:mainfrom
autodesk-forks:adsk/color_interop_naming
Aug 28, 2026
Merged

jstone-lucasfilm merged 7 commits into
AcademySoftwareFoundation:mainfrom
autodesk-forks:adsk/color_interop_naming

Conversation

@doug-walker

@doug-walker doug-walker commented Aug 17, 2026 •

Copy link
Copy Markdown
Contributor

As proposed at the August 11th TSC meeting, this PR brings to MaterialX full support for the ASWF Color Interop Forum recommendation Color Space Encodings for Texture Assets and CG Rendering that is used in other ASWF projects and OpenUSD. It supersedes PR #2514.

Support has been retained for all existing colorspace names and cmlib nodes.

Per the discussion at the TSC meeting, this PR does not upgrade existing documents when reading them to use the new names, however, that is still recommended as a follow-on step. Converting to the new names would likely simplify loading of MaterialX documents into OpenUSD. As things stand with this PR, the earlier MtlX names persist into the USD representation of the material, where they won't be recognized.

PR contents:

  • Adds color spaces and nodegraph implementations for "Linear Rec.2020", "ACES2065-1", "CIE XYZ-D65 - Scene-referred", and "sRGB Encoded AP1".
  • Since these are public-facing, existing stdlib nodedefs have been retained without changing their signature to the new name. The nodedefs for the new color spaces use the new names.
  • Improves the accuracy of the matrix converting P3 D65 to Rec.709 primaries.
  • Adds support for the Color Interop Forum "data" colorspace designation (equivalent to the earlier "none").
  • Adds ColorManagementSystem::isNoOpColorSpace to manage what colorspaces are no-ops (includes unit test). Note: this will break ABI-compatibility with the current release.
  • Adds ColorManagementSystem::getUserFacingName to convert the colorspace's color interop ID into a name suitable for use in a user interface.
  • Updates all documentation. Clarified that the rendering space is not guaranteed to be the document's working color space.
  • Adds new mtlx test files in resources/Materials/TestSuite/stdlib/color_management. All colorspace names (new and old) are tested. I validated the resulting renders against OCIO's built-in CG config for ACES.
  • Fixes the texture mapping in existing color management tests so that renders may be properly evaluated. Previously, some parts of the tests were not visible in the image because of where they were mapped onto the sphere.
  • Changes usage of "lin_rec709" to "lin_rec709_scene" in various .cpp modules that call targetColorSpaceOverride.

Notes:

  • All unit tests pass with MATERIALX_BUILD_OCIO both off and on.

Open questions:

  • I don't think the nodedefs/nodegraphs in libraries/cmlib should be public. They should more properly be considered part of the implementation of the DefaultColorManagementSystem. The fact that they only convert into Linear Rec.709 makes them fairly useless for people to use in MaterialX documents. In MaterialX.Proposals.md there is a proposed transformcolor node which potentially could be useful in documents, unlike the existing cmlib nodes.
  • I did not update references to the earlier color space names in the other .mtlx files in the repo, outside of the color_management test directory, but I'm open to doing so, just let me know.

Signed-off-by: Doug Walker <doug.walker@autodesk.com>
<?xml version="1.0"?>
<!--
Test that a colorspace on an image and on a color4 value work.
-->

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually a trimmed-down version of color_management.mtlx. I did a git mv on that file, so I'm surprised this is showing as a new file rather than as a rename of the existing one. The original "color_management" name was effectively meaningless and so I wanted to make it more precise.

I trimmed the test down to just a few values since the new all_colorspace_names.mtlx test is where we now test that all color space names are supported.

Signed-off-by: Doug Walker <doug.walker@autodesk.com>
Signed-off-by: Doug Walker <doug.walker@autodesk.com>
Signed-off-by: Doug Walker <doug.walker@autodesk.com>
Signed-off-by: Doug Walker <doug.walker@autodesk.com>
@doug-walker

Copy link
Copy Markdown
Contributor Author

@jstone-lucasfilm, I've made the changes to the nodedefs we discussed in the Nanocolor meeting. I updated the PR description accordingly.

@jstone-lucasfilm

jstone-lucasfilm commented Aug 22, 2026 •

Copy link
Copy Markdown
Member

Thanks for this substantial contribution, @doug-walker! I'll defer to you on the correctness of the new matrices, and it's very encouraging that you've validated that the values in all_colorspace_names.mtlx round-trip to the orange target color.

From an initial review, I see two potentially important issues to address:

The first is the default for ColorManagementSystem::isNoOpColorSpace. Before this change, populateColorTransformMap filtered "none" for every color management system, but with a base default of false, any subclass that doesn't override the new method (including the PyColorManagementSystem trampoline in the Python bindings) will be handed a transform from none to lin_rec709_scene, and shader generation will throw on documents that previously worked. Since none and data are reserved by the specification rather than by any particular CMS, I'd suggest the base class recognize them directly, with subclasses extending that set as the OCIO implementation does through isData(). Keeping the early return in populateColorTransformMap would also preserve the current behavior of leaving the port's color space unset, which otherwise flows into the OSL textureresource metadata and the GLSL/Slang uniform inputs.

The second is the potential cost of OCIO lookups. getSupportedColorSpaceName parses a full built-in config on every miss, and populateColorTransformMap now calls it up to four times per color port. Since lin_rec709_scene is a miss for any user config that predates the interop aliases in OCIO, a typical studio config would take the slow path on every color input. Your TODO already identifies this, but since this changelist is what makes the hot path hotter, I'd suggest addressing it here with a memo of resolved names in the implementation class.

A few smaller notes:

  1. The Python bindings should expose isNoOpColorSpace and getUserFacingName, with overrides in the trampoline class, since much of the UI code that would use the latter is in Python.
  2. The specification lists g18_ap1 and lin_srgb among the names that are "still supported", but cmlib has never provided graphs for either, so I'd suggest either dropping them or adding the trivial remaps. It may also be worth noting that none remains an accepted alias for data.
  3. The comment above CHECK(!colorManagementSystem->isNoOpColorSpace("Raw")) says the opposite of what the check asserts.

On your open questions: I agree that the cmlib graphs are more properly an implementation detail of the default CMS than a public node set, and I'd suggest we take that up as a change for a future MaterialX version bump (e.g. v2.x), so that we have the ability to provide upgrade logic to legacy documents. For the other .mtlx files in the repository, I'd suggest updating the ones that act as defaults for downstream documents, namely the colorspace attributes in pbrlib_defs.mtlx, the document color spaces in libraries/bxdf, and the srgb_texture default in creatematerial.py, with the example materials following in a later PR.

Finally, this work interacts with #3005, which adds a GenOptions::xyzToWorkingSpace transform for blackbody and thin-film shading. The XYZ-to-Rec.709 matrix there is a four-digit version of the one you've added to cmlib, and your table of linear working spaces is the natural source for deriving that default from the target color space. Your perspective on the white-point question in that thread would be valuable as well.

Overall this is an excellent proposal, and let's aim to include it in our v1.39.6 release.

Signed-off-by: Doug Walker <doug.walker@autodesk.com>
@doug-walker

Copy link
Copy Markdown
Contributor Author

Thank you for the careful review @jstone-lucasfilm! Totally agree with your findings, and I think they should all be addressed now. I will plan a separate PR to update names in the example materials, as you suggested.

I made a comment in #3005, I hope it was what you had in mind, please let me know if not.

@jstone-lucasfilm jstone-lucasfilm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks so much for this contribution, @doug-walker, and this looks good to me!

@jstone-lucasfilm
jstone-lucasfilm merged commit d23766b into AcademySoftwareFoundation:main Aug 28, 2026
36 checks passed
@doug-walker
doug-walker deleted the adsk/color_interop_naming branch August 29, 2026 01:59
jstone-lucasfilm added a commit to jstone-lucasfilm/MaterialX that referenced this pull request Sep 5, 2026
This changelist follows up on the color interop alignment in AcademySoftwareFoundation#3042, resolving a regression for documents that use legacy color space names such as `lin_rec709`.

With shader generation now targeting `lin_rec709_scene`, every color input in a legacy document was seen as requiring a transform, and the default color management system expressed the equivalence of these names as a pass-through `dot` node rather than omitting the transform.  This added a redundant node and renamed uniform for each color input, and in MDL it dropped the uniform qualifier from inputs such as glTF PBR `attenuation_color`, producing shaders that fail to compile.

The following specific changes are included:

- Add a virtual `ColorManagementSystem::isNoOpTransform` method, with a `DefaultColorManagementSystem` override that recognizes legacy and color interop names for the same color space, and consult it in `ShaderGraph` so that equivalent color spaces introduce no transform nodes.
- Preserve the uniform flag of an input when inserting a color or unit transform node, so that MDL declares the published value correctly.
- Update `TextureBaker` and the Metal render test to the `lin_rec709_scene` working space, with baked documents now written using color interop names.
- Expose `isNoOpTransform` in Python, with unit tests covering the alias logic and the generated GLSL and MDL shaders.
jstone-lucasfilm added a commit to jstone-lucasfilm/MaterialX that referenced this pull request Sep 5, 2026
This changelist follows up on the color interop alignment in AcademySoftwareFoundation#3042, resolving a regression for documents that use legacy color space names such as `lin_rec709`.

With shader generation now targeting `lin_rec709_scene`, every color input in a legacy document was seen as requiring a transform, and the default color management system expressed the equivalence of these names as a pass-through `dot` node rather than omitting the transform.  This added a redundant node and renamed uniform for each color input, and in MDL it dropped the uniform qualifier from inputs such as glTF PBR `attenuation_color`, producing shaders that fail to compile.

The following specific changes are included:

- Add a virtual `ColorManagementSystem::isNoOpTransform` method, with a `DefaultColorManagementSystem` override that recognizes legacy and color interop names for the same color space, and consult it in `ShaderGraph` so that equivalent color spaces introduce no transform nodes.
- Preserve the uniform flag of an input when inserting a color or unit transform node, so that MDL declares the published value correctly.
- Update `TextureBaker` and the Metal render test to the `lin_rec709_scene` working space, with baked documents now written using color interop names.
- Expose `isNoOpTransform` in Python, with unit tests covering the alias logic and the generated GLSL and MDL shaders.
jstone-lucasfilm added a commit to jstone-lucasfilm/MaterialX that referenced this pull request Sep 8, 2026
Following up on review notes from @doug-walker and @meshula, this changelist consolidates the `isNoOpColorSpace` and `isNoOpTransform` methods of `ColorManagementSystem` into a single `isNoOpTransform` query, and clarifies the comments and string literals of the new unit test.

Both methods were introduced in the color interop alignment of AcademySoftwareFoundation#3042 and have not yet shipped in a MaterialX release, so a single query covering both equivalent color space names and no-op color spaces is the simpler abstraction for both `ShaderGraph` and color management system implementations.

The following specific changes are included:

- Fold the no-op color space check into `ColorManagementSystem::isNoOpTransform`, which now returns true for identical names or when either name is a reserved no-op color space, and remove `isNoOpColorSpace` from the base class and Python bindings.
- Update the `DefaultColorManagementSystem` and `OcioColorManagementSystem` overrides to call their base implementations, with the OCIO override additionally recognizing color spaces flagged as data in the active config.
- Consult `isNoOpTransform` in `DefaultColorManagementSystem::getNodeDef`, so that the pass-through node returned to direct callers of `supportsTransform` and `createNode` follows the same rule as `ShaderGraph`, which omits these transforms entirely.
- Collapse the color space checks in `ShaderGraph::populateColorTransformMap` into a single `isNoOpTransform` query.
- Return by value from the `remapColorSpace` helper, removing a reference that would dangle if a caller passed a temporary.
jstone-lucasfilm added a commit that referenced this pull request Sep 9, 2026
This changelist follows up on the color interop alignment in #3042, resolving a regression for documents that use legacy color space names such as `lin_rec709`.

With shader generation now targeting `lin_rec709_scene`, every color input in a legacy document was seen as requiring a transform, and the default color management system expressed the equivalence of these names as a pass-through `dot` node rather than omitting the transform.  This added a redundant node and renamed uniform for each color input, and in MDL it dropped the uniform qualifier from inputs such as glTF PBR `attenuation_color`, producing shaders that fail to compile.

The following specific changes are included:

- Add a virtual `ColorManagementSystem::isNoOpTransform` method, with a `DefaultColorManagementSystem` override that recognizes legacy and color interop names for the same color space, and consult it in `ShaderGraph` so that equivalent color spaces introduce no transform nodes.
- Preserve the uniform flag of an input when inserting a color or unit transform node, so that MDL declares the published value correctly.
- Update `TextureBaker` and the Metal render test to the `lin_rec709_scene` working space, with baked documents now written using color interop names.
- Expose `isNoOpTransform` in Python, with unit tests covering the alias logic and the generated GLSL and MDL shaders.
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.

2 participants