SdrProperty UI Hints Metadata queries

Hey,

A question as to expected behaviour and whether we’re missing any API calls which are expected to be available for SdrProperties?

The issue is when trying to get the new uiHints from an SdrShaderProperty. Following the proposal: UI Hints in USD by agb63 · Pull Request #85 · PixarAnimationStudios/OpenUSD-proposals

    PXR_NS::SdrShaderNodeConstPtr node = PXR_NS::SdrRegistry::GetInstance().GetShaderNodeByIdentifier(PXR_NS::TfToken("TestShaderWithNestedMetadata"));
    if(node == nullptr) {
      std::cout << "Failed to find shader node 'TestShaderWithNestedMetadata' in registry." << std::endl;
      return metadata;
    }
    PXR_NS::SdrShaderPropertyConstPtr prop = node->GetShaderInput(PXR_NS::TfToken("colorIntensity"));
    PXR_NS::VtDictionary vtMetadata;
    for (const auto& [key, val] : prop->GetMetadataObject().GetItems()) {
      std::cout << "Metadata item: " << key << " : " << val.GetTypeName() << std::endl;
      vtMetadata[key] = val;
    }
    return fromVtDictionary(vtMetadata);

The result we get is:

Metadata item: connectable : bool
Metadata item: help : string
Metadata item: limits : string
Metadata item: sdrUsdDefinitionType : TfToken
Metadata item: uiHints : string
Metadata item: widget : TfToken

The issue is uiHints being a string, whereas we expect it should be a VtDictionary… We can’t necessarily see a way to get that as the nested VtDictionary it was defined as. If we print out the string it is:
"{'displayName': Intensity, 'hidden': 0}"

This makes it much harder to parse, and we believe possibly inconsistent, and we’re hesitant to implement parsing for this if this is not expected.
It’s also worth noting that this would not parse via Python dictionary (given Intensity is undefined, and has no quotes.)

Given there also isn’t any current shaders (which we could find) which utilise the new uiHints format, we had to make our own:

#usda 1.0

def Shader "TestShaderWithNestedMetadata" (
    sdrMetadata = {
        token role = "TestShaderWithNestedMetadata"
    }
)
{
    uniform token info:id = "TestShaderWithNestedMetadata"
    uniform token info:implementationSource = "sourceAsset"
    uniform asset info:glslfx:sourceAsset = @test.glslfx@

    float inputs:colorIntensity = 1.0 (
        sdrMetadata = {
            token help = "Controls the intensity of the output color"
            dictionary uiHints = {
                token displayName = "Intensity"
                bool hidden = 0
            }
            dictionary limits = {
                float min = 0.0
                float max = 100.0
            }
        }
    )
    color3f outputs:result
}
        from pxr import Sdr, Sdf, Usd, UsdShade
        # will need to define testDir.
        shaderLayerPath = os.path.join(testDir, "testShaderWithNestedMetadata.usda")

        stage = Usd.Stage.Open(shaderLayerPath)
        assert bool(stage), "Failed to open shader definition stage"

        shaderDef = UsdShade.Shader.Get(stage, Sdf.Path("/TestShaderWithNestedMetadata"))
        assert bool(shaderDef), "Shader definition prim not found"

        discoveryResults = UsdShade.ShaderDefUtils.GetDiscoveryResults(
            shaderDef, stage.GetRootLayer().realPath
        )
        assert len(discoveryResults) > 0, "No discovery results for shader definition"

        sdrRegistry = Sdr.Registry()
        for discoveryResult in discoveryResults:
            sdrRegistry.AddDiscoveryResult(discoveryResult)

(We used an almost empty glslfx file)

-- glslfx version 0.1
-- configuration
{"techniques": {"default": {}}}
-- This file is intentionally empty for testing purposes.

Is this an issue with how we’re registering a custom shader in order to test this functionality, or something I should raise as a bug to the OpenUSD Repo?

Cheers,
James

Hi @James,

Great callout, and thank you for the examples. Currently, uiHints is not fully integrated with SdrShaderProperty. The uiHints format was primarily developed to convey information on Usd objects.

In your example specifically, UsdShadeShader’s internal sdrMetadata representation is a simple token to string map, so any nesting of dictionaries is collapsed to a string representation as soon as it’s parsed.

I went ahead and opened an issue, which adds more information: Full integration of uiHints into SdrShaderProperty · Issue #4099 · PixarAnimationStudios/OpenUSD · GitHub .

I’m curious what you’re trying to do with uiHints in Sdr specifically – if you’re trying to convey information to UIs about shader properties while adhering to standards as much as possible, this is the current state of the art:

uiHints field Sdr equivalent
displayName SdrShaderPropertyMetadata::SetLabel
shownIf SdrShaderPropertyMetadata::SetShownIf
displayGroupsShownIf SdrShaderNodeMetadata::SetPagesShownIf
displayGroupsExpanded SdrShaderNodeMetadata::SetOpenPages
hidden no equivalent. You could do shownIf = 0 ?
valueLabels SdrShaderProperty::GetOptions (options are a vec of std::pair that gets set in the constructor. First item of each pair is the value label.)
valueLabelsOrder no equivalent.
limits:hard:minimum SdrShaderPropertyMetadata::SetItem(TfToken("min"), double)) This one’s tricky because the data type might not be the same for all properties with a min. double should be safe to use for everything though.
limits:hard:maximum SdrShaderPropertyMetadata::SetItem(TfToken("max"), double))
limits:soft:minimum SdrShaderPropertyMetadata::SetItem(TfToken("slidermin"), double))
limits:soft:maximum SdrShaderPropertyMetadata::SetItem(TfToken("sliermax"), double))
arraySizeConstraint It’s complicated and I don’t quite get it, but here’s the current translation. You could probably get away with just setting arraySize in the SdrShaderProperty constructor.

Current SdrShaderProperty metadata definitions and expected formats are documented here: https://openusd.org/release/api/\_sdr__shader_property.html#Sdr_ShaderProperty_Metadata

Hopefully that answers your question?