Autodesk / maya-usd

A common USD (Universal Scene Description) plugin for Autodesk Maya
759 stars 202 forks source link

[EMSUSD-637] MayaUSDExportCommand doesn't export 'default' value of USD_ATTR_purpose correctly #3332

Open joebrownjf opened 12 months ago

joebrownjf commented 12 months ago

Describe the bug If we set the attribute USD_ATTR_purpose to default, which is described as a valid value in the MayaUSDExportCommand documentation, the resulting USD file has a blank entry for that field. Setting the attribute to other values described in the docs, or even strings not mentioned in the docs, will result in that value being written into the exported USD file. Only the default value will result in a blank field (as far as my testing shows).

Steps to reproduce Steps to reproduce the behavior:

cmds.polyPlane(name="testPlane", sx=1, sy=1)
cmds.addAttr("testPlane", longName="USD_ATTR_purpose", dataType="string")

cmds.setAttr("testPlane.USD_ATTR_purpose", "render", type='string')
cmds.mayaUSDExport(file=r"C:\tmp\usd_purpose_render.usda", exportRoots=["testPlane"])
cmds.setAttr("testPlane.USD_ATTR_purpose", "default", type='string')
cmds.mayaUSDExport(file=r"C:\tmp\usd_purpose_default.usda", exportRoots=["testPlane"])
cmds.setAttr("testPlane.USD_ATTR_purpose", "foo", type='string')
cmds.mayaUSDExport(file=r"C:\tmp\usd_purpose_foo.usda", exportRoots=["testPlane"])

Execute the above python in a new scene, substituting the output file paths to suit your setup. Open and observe the results, as below (truncated for brevity).

usd_purpose_render.usda:

#usda 1.0
(
    defaultPrim = "testPlane"
    metersPerUnit = 0.01
    upAxis = "Y"
)

def Mesh "testPlane" (
    prepend apiSchemas = ["MaterialBindingAPI"]
    kind = "component"
)
{
    uniform bool doubleSided = 1
    float3[] extent = [(-0.5, 0, -0.5), (0.5, 0, 0.5)]
    int[] faceVertexCounts = [4]
    int[] faceVertexIndices = [0, 1, 3, 2]
    rel material:binding = </testPlane/mtl/initialShadingGroup>
    point3f[] points = [(-0.5, 0, 0.5), (0.5, 0, 0.5), (-0.5, 0, -0.5), (0.5, 0, -0.5)]
    texCoord2f[] primvars:st = [(0, 0), (1, 0), (0, 1), (1, 1)] (
        customData = {
            dictionary Maya = {
                token name = "map1"
            }
        }
        interpolation = "faceVarying"
    )
    int[] primvars:st:indices = [0, 1, 3, 2]
    uniform token purpose = "render"

    def Scope "mtl"
    {
        def Material "initialShadingGroup"
        {
        }
    }
}

usd_purpose_default.usda:

#usda 1.0
...
def Mesh "testPlane" (
    ...
)
{
    ...
    uniform token purpose
    ...

}

usd_purpose_foo.usda:

#usda 1.0
...
def Mesh "testPlane" (
    ...
)
{
   ...
    uniform token purpose = "foo"
    ...
}

Expected behavior I would expect the value default to be written into the field for that value. Default is a valid purpose and is different to an empty field, as when it comes to composition I may wish to override this field, from a lower layer in the stack, e.g. from proxy to default, but this is impossible as setting to attribute to default results in a blank field, which on composition will fallback to the other layer.

Specs (if applicable):

santosg87 commented 11 months ago

Thank you for reporting this! I have logged an internal ticket to track the issue (EMSUSD-637).

The main question for us here is regarding fixing this - and changing the behavior for anyone who might have built tools around the issue. We need to understand the implications of changing the default behavior of simply using an empty token, but this does indeed seem not to be the right way of writing the default purpose.

joebrownjf commented 11 months ago

What would be the use case that would take advantage of it being blank even when set to default? The same behaviour could be achieved by leaving the attribute field blank, so any existing tooling could be changed to do that. I would argue that this is ultimately a bug, as the behaviour doesn't match the documentation or expected behaviour.

I'm struggling to picture the motivation for any tooling to be deliberately writing 'default' into this attribute in order to get the result of a blank field in the export. I would also posit that it's a safe bet that no one with a pipeline that relies on such details is going to install and start using the latest version of the plugin without reading the changelog.

wallworm commented 11 months ago

We looked into this and thing that it's actually not a defect. There is a flag available that will do what you want: writeDefaults=true

cmds.mayaUSDExport(file=r"usd_purpose_default.usda", exportRoots=["testPlane"], writeDefaults=True)

Please let me know if this solves your problem.

maya-usd-git-sync[bot] commented 10 months ago

Issue synced internally to EMSUSD-815