PixarAnimationStudios / OpenUSD

Universal Scene Description

Home Page:http://www.openusd.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

usdMtlx does not consistently preserve MaterialX node names

dgovil opened this issue · comments

Description of Issue

When I convert a .mtlx document to USD, the resulting graph does not preserve the name.

Take this example here and note that the UsdPreviewSurface node has a specified name SR_brass1.
Also note that the tileimage nodes both have a name image_roughness and image_color.

<?xml version="1.0"?>
<materialx version="1.38" colorspace="lin_rec709">
  <nodegraph name="NG_brass1" fileprefix="../../../Images/">
    <tiledimage name="image_color" type="color3">
      <input name="file" type="filename" value="brass_color.jpg" colorspace="srgb_texture" />
      <input name="uvtiling" type="vector2" value="1.0, 1.0" />
    </tiledimage>
    <tiledimage name="image_roughness" type="float">
      <input name="file" type="filename" value="brass_roughness.jpg" />
      <input name="uvtiling" type="vector2" value="1.0, 1.0" />
    </tiledimage>
    <output name="out_color" type="color3" nodename="image_color" />
    <output name="out_roughness" type="float" nodename="image_roughness" />
  </nodegraph>
  <UsdPreviewSurface name="SR_brass1" type="surfaceshader">
    <input name="diffuseColor" type="color3" nodegraph="NG_brass1" output="out_color" />
    <input name="metallic" type="float" value="1" />
    <input name="roughness" type="float" nodegraph="NG_brass1" output="out_roughness" />
  </UsdPreviewSurface>
  <surfacematerial name="USD_Tiled_Brass" type="material">
    <input name="surfaceshader" type="surfaceshader" nodename="SR_brass1" />
  </surfacematerial>
</materialx>

When converted to USD, I get the following hierarchy (from usdtree)

/
 `--MaterialX [def]
     |--Materials [def]
     |   `--USD_Tiled_Brass [def Material]
     |       |--ND_UsdPreviewSurface_surfaceshader [def Shader]
     |       `--NG_brass1 [def NodeGraph]
     |           |--image_color [def Shader]
     |           `--image_roughness [def Shader]
     |--Shaders [def]
     |   `--ND_UsdPreviewSurface_surfaceshader [def Shader]
     `--NodeGraphs [def]
         `--NG_brass1 [def NodeGraph]
             |--image_color [def Shader]
             `--image_roughness [def Shader]

Notice that the two tiled image nodes have preserved their names from the mtlx document. However the USDPreviewSurface has eschewed its name and instead picked the node definition as the name instead.

This seems inconsisent and makes it difficult to predict the output graph when looking at the MaterialX document.

Steps to Reproduce

  1. Convert any sample .mtlx file to USD using usdcat

System Information (OS, Hardware)

Tested with USD 24.3 and 24.5 on macOS.

Hi @dgovil , we don't recall the reason for this... closest recollection is that we had some possibly confusion about the need/identity for NodeGraphs for mtlx Materials. In any case, we agree it's unfortunate, and are open to a PR that addresses it, maybe with a FF arg to preserve the old behavior for existing documents... though it feels like we're putting/contemplating alot of switches on this plugin.

Thanks for the response. I agree that it would be good to avoid putting too many switches in.

I was thinking perhaps a good solution is to use an env variable instead for this and give it a deprecation period?

E.g Something like PXR_USDMTLX_LEGACY_SHADER_NAME to opt into the current naming, and when set it emits a warning like "This option will be removed in USD (current year+1). Please convert your mtlx files with usdcat if you need to rely on this naming."

That way we don't bake in the switch into any files and give people a time boxed off ramp at the same time.

I think now's a good time to do it while use of mixed USD+MTLX files outside of studios is going to be low.

If that sounds reasonable, I can put up a PR accordingly.

Filed as internal issue #USD-9713

If that flies with the #wg-usd-materialx community, it sounds good to me. Looks like you've already begun discussing and that @JGamache-autodesk may add thoughts here, also?

I was wondering what would happen if there were multiple standard surface nodes in the document. Looks like they all resolve to a single /MaterialX/Shaders/ND_UsdPreviewSurface_surfaceshader that gets referenced in all materials, and all references get to be named ND_UsdPreviewSurface_surfaceshader because they are in the namespace of the material. Unsure if this helps since it looks like those nodes only get an info:id and a outputs:surface attribute (which does not necessarily match the name of the output referenced in the shader registry).

Looks like the mindset for the current importer is very material-centric. The name of the surfacematerial node is all that matters. The way the loader transfers all input parameters to the UsdMaterial is also strange. The UsdShade node, via its SdrShader reference knows how to display itself in an inspector. Once all those attributes are transferred to the material we lose information like the uimin and uimax of the attributes unless the inspector makes a special case for UsdMaterial and peeks under the connections to find what shader node is referenced.

We can either start adding a lot of attributes on the loader, or environment variables to switch behaviors as we rework the loader, but I think an option to have multiple loaders for a .mtlx file, along with a way to register and select which loader to use could be interesting if we want to preserve the initial behavior while exploring new ways to ingest MaterialX.

@JGamache-autodesk , I wanted to respond to this:

The way the loader transfers all input parameters to the UsdMaterial is also strange. The UsdShade node, via its SdrShader reference knows how to display itself in an inspector. Once all those attributes are transferred to the material we lose information like the uimin and uimax of the attributes unless the inspector makes a special case for UsdMaterial and peeks under the connections to find what shader node is referenced.

Constructing a "public material interface" on the Material prim is a crucial part of the UsdShade OM. As discussed with @dgovil in either a slack thread or the forum, it provides artists the ability to centralize and customize the "expected to be tweaked" interface. And it is vital for "instanced materials" to be useful at all, because there, the only prim available for editing is the Material prim itself.

That said, we do indeed have the awkwardness of access to the auxiliary data for each input that we provide for users to interact with. We do the majority of our editing in an application that is built on the Presto framework, which reads in the USD data directly, but presents it ona "Presto stage", and Presto stages provide cached "back pointers" for all relationships and connections, and Presto's Inspector editor has a fair amount of custom code - for Material prims it does just what you describe: it hops across the connection to find the Sdr-configured Shader property and configure the presentation of the Material property accordingly.

That is not a very satisfying answer for many reasons, I know, especially because UsdAttribute/UsdRelationship provide no such back pointers (as they are incredibly expensive to compute and cache for the whole stage). However, I think we'd be open to adding (especially via PR) a UsdShade or UsdShadeMaterial utility that would do all the necessary work for you for a Material at a time and return a map of attribute-name to SdrShaderProperty (or a dictionary of its metadata). In fact, I think we used to provide a similar utility that was needed by the Katana ingest of UsdShade, but we moved it the katana plugins at some point (and it wasn't quite what we're talking about here, but close).

Need to think more about your other points...