def getRegistry(cls): if cls._reg is None: try: cls._reg = Sdr.Registry() except: pass return cls._reg
def test_Registry(self): """ Test basic registry operations. Also ensures that the discovery process works correctly. """ # Register test plugins and verify they have been found pr = Plug.Registry() plugins = pr.RegisterPlugins(testPluginsDsoSearch) # Verify the test plugins have been found. When building monolithic # we should find at least these derived types. self.assertEqual(len(plugins), 1) fsdpType = Tf.Type.FindByName('_NdrFilesystemDiscoveryPlugin') tdpType = Tf.Type.FindByName('_NdrTestDiscoveryPlugin') self.assertEqual( set([fsdpType, tdpType]) - set(pr.GetAllDerivedTypes('NdrDiscoveryPlugin')), set()) self.assertEqual( set([ Tf.Type.FindByName('_NdrArgsTestParserPlugin'), Tf.Type.FindByName('_NdrOslTestParserPlugin') ]) - set(pr.GetAllDerivedTypes('NdrParserPlugin')), set()) # Instantiating the registry will kick off the discovery process. # This test assumes the PXR_NDR_SKIP_DISCOVERY_PLUGIN_DISCOVERY has # been set prior to being run to ensure built-in plugins are not # found. Instead we'll list the plugins we want explicitly. # Setting this from within the script does not work on Windows. # os.environ["PXR_NDR_SKIP_DISCOVERY_PLUGIN_DISCOVERY"] = "" reg = Sdr.Registry() reg.SetExtraDiscoveryPlugins([fsdpType, tdpType]) nodes = reg.GetShaderNodesByFamily() assert len(nodes) == 4 assert reg.GetSearchURIs() == ["/TestSearchPath"] assert set(reg.GetNodeNames()) == { "TestNodeARGS", "TestNodeOSL", "TestNodeSameName" } assert id(reg.GetShaderNodeByURI(nodes[0].GetSourceURI())) == id( nodes[0]) assert id(reg.GetShaderNodeByName(nodes[0].GetName())) == id(nodes[0]) argsType = "RmanCpp" oslType = "OSL" # Ensure that the registry can retrieve two nodes of the same name but # different source types assert {argsType, oslType}.issubset(set(reg.GetAllNodeSourceTypes())) assert len(reg.GetShaderNodesByName("TestNodeSameName")) == 2 assert reg.GetShaderNodeByNameAndType("TestNodeSameName", oslType) is not None assert reg.GetShaderNodeByNameAndType("TestNodeSameName", argsType) is not None assert reg.GetShaderNodeByName("TestNodeSameName", [oslType, argsType])\ .GetSourceType() == oslType assert reg.GetShaderNodeByName("TestNodeSameName", [argsType, oslType])\ .GetSourceType() == argsType
def setUpClass(cls): """ Load the test modules for discovery and parsing and check basic type registration """ # Register test plugins and verify they have been found cls.pr = Plug.Registry() plugins = cls.pr.RegisterPlugins(testPluginsDsoSearch) # Verify the test plugins have been found. When building monolithic # we should find at least these derived types. assert len(plugins) == 1 cls.tdpType = Tf.Type.FindByName('_NdrTestDiscoveryPlugin') cls.tdp2Type = Tf.Type.FindByName('_NdrTestDiscoveryPlugin2') cls.tppType = Tf.Type.FindByName('_NdrArgsTestParserPlugin') cls.tpp2Type = Tf.Type.FindByName('_NdrOslTestParserPlugin') # We don't check for all the derived types of NdrDiscoveryPlugin # because this test only uses the discovery and parser plugins # that are defined in this testenv assert {cls.tdpType, cls.tdp2Type}.issubset( set(cls.pr.GetAllDerivedTypes('NdrDiscoveryPlugin'))) assert {cls.tppType, cls.tpp2Type }.issubset(set(cls.pr.GetAllDerivedTypes('NdrParserPlugin'))) # Instantiating the registry will kick off the discovery process. # This test assumes the PXR_NDR_SKIP_DISCOVERY_PLUGIN_DISCOVERY # and PXR_NDR_SKIP_PARSER_PLUGIN_DISCOVERY has been set prior to # being run to ensure built-in plugins are not found. Instead # we'll list the plugins we want explicitly. # Setting this from within the script does not work on Windows. # os.environ["PXR_NDR_SKIP_DISCOVERY_PLUGIN_DISCOVERY"] = "" # os.environ["PXR_NDR_SKIP_PARSER_PLUGIN_DISCOVERY"] = "" cls.reg = Sdr.Registry() # Set up the test parser plugins. cls.reg.SetExtraParserPlugins([cls.tppType, cls.tpp2Type]) # We will register the discovery plugins one by one so that we can check # source types are not duplicated in the registry if we have plugins # that discover nodes of the same source type # The _NdrTestDiscoveryPlugin should find discovery results that have # source types of RmanCpp and OSL cls.reg.SetExtraDiscoveryPlugins([cls.tdpType]) assert sorted(cls.reg.GetAllNodeSourceTypes()) == \ [cls.oslType, cls.argsType] # The _NdrTestDiscoveryPlugin2 should find discovery results that have # source types of RmanCpp and glslfx cls.reg.SetExtraDiscoveryPlugins([cls.tdp2Type])
def test_Registry(self): """ Test basic registry operations. Also ensures that the discovery process works correctly. """ # Register test plugins and verify they have been found pr = Plug.Registry() plugins = pr.RegisterPlugins(testPluginsDsoSearch) self.assertEqual(len(plugins), 1) self.assertEqual( set(pr.GetAllDerivedTypes('NdrDiscoveryPlugin')), set([ Tf.Type.FindByName('_NdrFilesystemDiscoveryPlugin'), Tf.Type.FindByName('_NdrTestDiscoveryPlugin') ])) self.assertEqual( set(pr.GetAllDerivedTypes('NdrParserPlugin')), set([ Tf.Type.FindByName('_NdrArgsTestParserPlugin'), Tf.Type.FindByName('_NdrOslTestParserPlugin') ])) # Instantiating the registry will kick off the discovery process reg = Sdr.Registry() nodes = reg.GetShaderNodesByFamily() assert len(nodes) == 4 assert reg.GetSearchURIs() == ["/TestSearchPath"] assert set(reg.GetNodeNames()) == { "TestNodeARGS", "TestNodeOSL", "TestNodeSameName" } assert id(reg.GetShaderNodeByURI(nodes[0].GetSourceURI())) == id( nodes[0]) assert id(reg.GetShaderNodeByName(nodes[0].GetName())) == id(nodes[0]) argsType = "RmanCpp" oslType = "OSL" # Ensure that the registry can retrieve two nodes of the same name but # different source types assert {argsType, oslType}.issubset(set(reg.GetAllNodeSourceTypes())) assert len(reg.GetShaderNodesByName("TestNodeSameName")) == 2 assert reg.GetShaderNodeByNameAndType("TestNodeSameName", oslType) is not None assert reg.GetShaderNodeByNameAndType("TestNodeSameName", argsType) is not None assert reg.GetShaderNodeByName("TestNodeSameName", [oslType, argsType])\ .GetSourceType() == oslType assert reg.GetShaderNodeByName("TestNodeSameName", [argsType, oslType])\ .GetSourceType() == argsType
def test_Basic(self): r = Sdr.Registry() uvTextureNode = r.GetNodeByName('UsdUVTexture', ['OSL']) self.assertTrue(uvTextureNode) self.assertEqual( uvTextureNode.GetInputNames(), ['file', 'st', 'wrapS', 'wrapT', 'fallback', 'scale', 'bias']) primvarReaderNode = r.GetNodeByName('UsdPrimvarReader_float', ['OSL']) self.assertTrue(primvarReaderNode) self.assertEqual(primvarReaderNode.GetInputNames(), ['varname', 'fallback'])
def test_NodeParser(self): """ Test MaterialX node parser. """ # Let the plugin discover our nodes. searchPath = os.getcwd() os.environ['PXR_USDMTLX_PLUGIN_SEARCH_PATHS'] = searchPath # Find our nodes. nodes = Sdr.Registry().GetShaderNodesByFamily('UsdMtlxTestNode') self.assertEqual(sorted([node.GetName() for node in nodes]), [ 'nd_boolean', 'nd_customtype', 'nd_float', 'nd_integer', 'nd_string', 'nd_surface', 'nd_vector', ]) # Verify common info. for node in nodes: self.assertEqual(node.GetSourceType(), "OSL") self.assertEqual(node.GetFamily(), "UsdMtlxTestNode") self.assertEqual(sorted(node.GetInputNames()), ["in", "note"]) if node.GetName() == 'nd_surface': # XXX -- Should shader semantic nodes have a named output? self.assertEqual(node.GetOutputNames(), []) else: self.assertEqual(node.GetOutputNames(), ["result"]) # Verify converted types. typeNameMap = { 'boolean': 'bool', 'customtype': 'customtype', 'float': 'float', 'integer': 'int', 'string': 'string', 'surface': 'string', 'vector': 'vector', } for node in nodes: # Strip leading nd_ from name. name = node.GetName()[3:] # Get the input. prop = node.GetInput('in') # Verify type. self.assertEqual(prop.GetType(), typeNameMap.get(name))
def test_GetShaderNodeFromAsset(self): """ Test that invoking the parser to identify shader definitions from an asset file works when specifying a subIdentifier and sourceType """ reg = Sdr.Registry() node = reg.GetShaderNodeFromAsset( "shaderDefs.usda", # shaderAsset {}, # metadata "TestShaderPropertiesNodeUSD", # subIdentifier "glslfx" # sourceType ) assert node is not None assert node.GetIdentifier().endswith( "<TestShaderPropertiesNodeUSD><glslfx>")
def test_NodeParser(self): """ Test MaterialX node parser. """ # Find our nodes. nodes = Sdr.Registry().GetShaderNodesByFamily('UsdMtlxTestNode') self.assertEqual(sorted([node.GetName() for node in nodes]), [ 'UsdMtlxTestNamespace:nd_boolean', 'UsdMtlxTestNamespace:nd_customtype', 'UsdMtlxTestNamespace:nd_float', 'UsdMtlxTestNamespace:nd_integer', 'UsdMtlxTestNamespace:nd_string', 'UsdMtlxTestNamespace:nd_surface', 'UsdMtlxTestNamespace:nd_vector', ]) # Verify common info. for node in nodes: implementationUri = node.GetResolvedImplementationURI() self.assertEqual(os.path.normcase(implementationUri), os.path.normcase(os.path.abspath("test.mtlx"))) self.assertEqual(node.GetSourceType(), "mtlx") self.assertEqual(node.GetFamily(), "UsdMtlxTestNode") self.assertEqual(sorted(node.GetInputNames()), ["in", "note"]) self.assertEqual(node.GetOutputNames(), ['out']) # Verify converted types. typeNameMap = { 'boolean': 'bool', 'customtype': 'customtype', 'float': 'float', 'integer': 'int', 'string': 'string', 'surface': 'string', 'vector': 'float', # vector actually becomes a float[3], but the # array size is not represented in the Type } for node in nodes: # Strip leading UsdMtlxTestNamespace:nd_ from name. name = node.GetName()[24:] # Get the input. prop = node.GetInput('in') # Verify type. self.assertEqual(prop.GetType(), typeNameMap.get(name))
def getRegistry(cls): if cls._reg is None: cls._reg = Sdr.Registry() return cls._reg
def test_Registry(self): """ Test basic registry operations. Also ensures that the discovery process works correctly. """ # Register test plugins and verify they have been found pr = Plug.Registry() plugins = pr.RegisterPlugins(testPluginsDsoSearch) # Verify the test plugins have been found. When building monolithic # we should find at least these derived types. self.assertEqual(len(plugins), 1) tdpType = Tf.Type.FindByName('_NdrTestDiscoveryPlugin') tdp2Type = Tf.Type.FindByName('_NdrTestDiscoveryPlugin2') tppType = Tf.Type.FindByName('_NdrArgsTestParserPlugin') tpp2Type = Tf.Type.FindByName('_NdrOslTestParserPlugin') # We don't check for all the derived types of NdrDiscoveryPlugin # because this test only uses the discovery and parser plugins # that are defined in this testenv assert {tdpType, tdp2Type }.issubset(set(pr.GetAllDerivedTypes('NdrDiscoveryPlugin'))) assert {tppType, tpp2Type }.issubset(set(pr.GetAllDerivedTypes('NdrParserPlugin'))) # The following source types are what we expect to discover from # _NdrTestDiscoveryPlugin and _NdrTestDiscoveryPlugin2. Note that there # is no glslfx parser plugin provided in this test. argsType = "RmanCpp" oslType = "OSL" glslfxType = "glslfx" # Instantiating the registry will kick off the discovery process. # This test assumes the PXR_NDR_SKIP_DISCOVERY_PLUGIN_DISCOVERY # and PXR_NDR_SKIP_PARSER_PLUGIN_DISCOVERY has been set prior to # being run to ensure built-in plugins are not found. Instead # we'll list the plugins we want explicitly. # Setting this from within the script does not work on Windows. # os.environ["PXR_NDR_SKIP_DISCOVERY_PLUGIN_DISCOVERY"] = "" # os.environ["PXR_NDR_SKIP_PARSER_PLUGIN_DISCOVERY"] = "" reg = Sdr.Registry() # Set up the test parser plugins. reg.SetExtraParserPlugins([tppType, tpp2Type]) # We will register the discovery plugins one by one so that we can check # source types are not duplicated in the registry if we have plugins # that discover nodes of the same source type # The _NdrTestDiscoveryPlugin should find discovery results that have # source types of RmanCpp and OSL reg.SetExtraDiscoveryPlugins([tdpType]) assert reg.GetAllNodeSourceTypes() == [oslType, argsType] # The _NdrTestDiscoveryPlugin2 should find discovery results that have # source types of RmanCpp and glslfx reg.SetExtraDiscoveryPlugins([tdp2Type]) # Test that the registry does not see 'RmanCpp' twice as a source type, # and that it finds 'glslfx' as a source type assert reg.GetAllNodeSourceTypes() == [oslType, argsType, glslfxType] # Calling SdrRegistry::GetShaderNodesByFamily() will actually parse the # discovery results. # Notice that in the five node names we find, we get 'TestNodeSameName' # twice because there are two nodes with different source types that # have the same name. # Notice that we do not see 'TestNodeGLSLFX' because we don't have a # parser plugin to support it nodes = reg.GetShaderNodesByFamily() shaderNodeNames = [node.GetName() for node in nodes] assert set(shaderNodeNames) == { "TestNodeARGS", "TestNodeARGS2", "TestNodeOSL", "TestNodeSameName", "TestNodeSameName" } assert reg.GetSearchURIs() == ["/TestSearchPath", "/TestSearchPath2"] # Calling SdrRegistry::GetNodeNames only looks at discovery results # without parsing them. # Notice that we get 'TestNodeSameName' only once because we only show # unique names. # Notice that we see 'TestNodeGLSLFX' because it is in our discovery # results even though we do not have a parser plugin that supports its # source type. assert set(reg.GetNodeNames()) == { "TestNodeARGS", "TestNodeARGS2", "TestNodeOSL", "TestNodeSameName", "TestNodeGLSLFX" } assert id(reg.GetShaderNodeByName(nodes[0].GetName())) == id(nodes[0]) # Ensure that the registry can retrieve two nodes of the same name but # different source types assert len(reg.GetShaderNodesByName("TestNodeSameName")) == 2 assert reg.GetShaderNodeByNameAndType("TestNodeSameName", oslType) is not None assert reg.GetShaderNodeByNameAndType("TestNodeSameName", argsType) is not None assert reg.GetShaderNodeByName("TestNodeSameName", [oslType, argsType])\ .GetSourceType() == oslType assert reg.GetShaderNodeByName("TestNodeSameName", [argsType, oslType])\ .GetSourceType() == argsType # Test GetShaderNodeFromAsset to check that a subidentifier is part of # the node's identifier if one is specified node = reg.GetShaderNodeFromAsset( Sdf.AssetPath('TestNodeSourceAsset.oso'), # shaderAsset {}, # metadata "mySubIdentifier") # subIdentifier assert node.GetIdentifier().endswith("<mySubIdentifier><>") # Test GetShaderNodeFromAsset to check that a sourceType is part of # the node's identifier if one is specified node = reg.GetShaderNodeFromAsset( Sdf.AssetPath('TestNodeSourceAsset.oso'), # shaderAsset {}, # metadata "mySubIdentifier", # subIdentifier "OSL") # sourceType assert node.GetIdentifier().endswith("<mySubIdentifier><OSL>")
# Note that for nodes with explicit asset paths, this list stores a tuple, # with first entry being the sdrNode and second the true identifier # (identified from the file basename, which should match the node identifier # when queries using GetShaderNodeByIdentifierAndType at runtime). sdrNodesToParse = [] renderContext = "" sdrNodesDict = config.get(SchemaConfigConstants.SDR_NODES) if sdrNodesDict: # Extract any renderContext from the config if specified. if SchemaConfigConstants.RENDER_CONTEXT in sdrNodesDict.keys(): renderContext = \ sdrNodesDict.get(SchemaConfigConstants.RENDER_CONTEXT) # Extract sdrNodes from the config sdrRegistry = Sdr.Registry() for sourceType in sdrNodesDict.keys(): if sourceType == SchemaConfigConstants.RENDER_CONTEXT: continue if sourceType == SchemaConfigConstants.SOURCE_ASSET_NODES: # process sdrNodes provided by explicit sourceAssetNodes for assetPath in \ sdrNodesDict.get(SchemaConfigConstants.SOURCE_ASSET_NODES): node = Sdr.Registry().GetShaderNodeFromAsset(assetPath) nodeIdentifier = \ os.path.splitext(os.path.basename(assetPath))[0] if node: sdrNodesToParse.append((node, nodeIdentifier)) else: Tf.Warn("Node not found at path: %s." % (assetPath)) continue
# Parse json config to extract sdrNodes and schema sublayers try: with open(schemaConfig) as json_file: config = json.load(json_file) except ValueError as ve: Tf.RaiseRuntimeError("Error loading (%s), value error: (%s)" \ %(schemaConfig, ve)) if not isinstance(config, dict): Tf.Warn("Invalid json config provided, expecting a dictionary") sys.exit(1) sdrNodesToParse = [] if config.has_key("sdrNodes"): sdrRegistry = Sdr.Registry() for sourceType in config['sdrNodes'].keys(): for nodeId in config['sdrNodes'][sourceType]: node = sdrRegistry.GetShaderNodeByNameAndType( nodeId, sourceType) if node: sdrNodesToParse.append(node) else: Tf.Warn("Invalid Node (%s:%s) provided." % (sourceType, nodeId)) else: Tf.Warn("No sdr nodes provided to generate a schema.usda") sys.exit(1) if not sdrNodesToParse: Tf.Warn("No valid sdr nodes provided to generate a schema.usda")
def UpdateSchemaWithSdrNode(schemaLayer, sdrNode): """ Updates the given schemaLayer with primSpec and propertySpecs from sdrNode metadata. It consume the following attributes (that manifest as Sdr metadata) in addition to many of the standard Sdr metadata specified and parsed (via its parser plugin). Node Level Metadata: - "schemaName": Name of the new schema populated from the given sdrNode (Required) - "schemaKind": Specifies the UsdSchemaKind for the schema being populated from the sdrNode. (note that this does not support multi-applied schema kinds). - "schemaBase": Base schema from which the new schema should inherit from. Note this defaults to "APISchemaBase" for an api schema or "Typed" for a concrete scheme. - "usdSchemaClass": Specified the equivalent schema directly generated by USD (sourceType: USD). This is used to make sure duplicate properties already specified in the USD schema are not populated in the new API schema. Note this is only used when we are dealing with an API schema. - "apiSchemaAutoApplyTo": The Schemas to which the sdrNode populated (API) schema will autoApply to. - "tfTypeNameSuffix": Class name which will get registered with TfType system. This gets appended to the domain name to register with TfType. Property Level Metadata: USD_VARIABILITY = A property level metadata, which specified a specific sdrNodeProperty should its usd variability set to Uniform or Varying. """ # Early exit on invalid parameters if not schemaLayer: Tf.Warn("No Schema Layer provided") return if not sdrNode: Tf.Warn("No valid sdrNode provided") return sdrNodeMetadata = sdrNode.GetMetadata() if not sdrNodeMetadata.has_key(SchemaDefiningKeys.SCHEMA_NAME): Tf.Warn("Sdr Node does not define a schema name metadata.") return schemaName = sdrNodeMetadata[SchemaDefiningKeys.SCHEMA_NAME] if not Tf.IsValidIdentifier(schemaName): Tf.RaiseRuntimeError( "schemaName (%s) is an invalid identifier; " "Provide a valid USD identifer for schemaName, example (%s) " % (schemaName, Tf.MakeValidIdentifier(schemaName))) tfTypeNameSuffix = None if sdrNodeMetadata.has_key(SchemaDefiningKeys.TF_TYPENAME_SUFFIX): tfTypeNameSuffix = sdrNodeMetadata[ SchemaDefiningKeys.TF_TYPENAME_SUFFIX] if not Tf.IsValidIdentifier(tfTypeNameSuffix): Tf.RaiseRuntimeError("tfTypeNameSuffix (%s) is an invalid " \ "identifier" %(tfTypeNameSuffix)) if not sdrNodeMetadata.has_key(SchemaDefiningKeys.SCHEMA_KIND): schemaKind = SchemaDefiningMiscConstants.TYPED_SCHEMA else: schemaKind = sdrNodeMetadata[SchemaDefiningKeys.SCHEMA_KIND] # Note: We are not working on dynamic multiapply schemas right now. isAPI = schemaKind == SchemaDefiningMiscConstants.SINGLE_APPLY_SCHEMA # Fix schemaName and warn if needed if isAPI and \ not schemaName.endswith(SchemaDefiningMiscConstants.API_STRING): Tf.Warn("node metadata implies the generated schema being created is " "an API schema, fixing schemaName to reflect that") schemaName = schemaName + SchemaDefiningMiscConstants.API_STRING if isAPI and tfTypeNameSuffix and \ not tfTypeNameSuffix.endswith(SchemaDefiningMiscConstants.API_STRING): Tf.Warn("node metadata implies the generated schema being created " "is an API schema, fixing tfTypeNameSuffix to reflect that") tfTypeNameSuffix = tfTypeNameSuffix + \ SchemaDefiningMiscConstants.API_STRING if not sdrNodeMetadata.has_key(SchemaDefiningKeys.SCHEMA_BASE): Tf.Warn("No schemaBase specified in node metadata, defaulting to " "APISchemaBase for API schemas else Typed") schemaBase = SchemaDefiningMiscConstants.API_SCHEMA_BASE if isAPI \ else SchemaDefiningMiscConstants.TYPED_SCHEMA else: schemaBase = sdrNodeMetadata[SchemaDefiningKeys.SCHEMA_BASE] apiSchemaAutoApplyTo = None if sdrNodeMetadata.has_key(SchemaDefiningKeys.API_SCHEMA_AUTO_APPLY_TO): apiSchemaAutoApplyTo = \ sdrNodeMetadata[SchemaDefiningKeys.API_SCHEMA_AUTO_APPLY_TO] \ .split('|') usdSchemaClass = None if isAPI and sdrNodeMetadata.has_key(SchemaDefiningKeys.USD_SCHEMA_CLASS): usdSchemaClass = \ sdrNodeMetadata[SchemaDefiningKeys.USD_SCHEMA_CLASS] primSpec = schemaLayer.GetPrimAtPath(schemaName) if (primSpec): # if primSpec already exist, remove entirely and recreate using the # parsed sdr node if primSpec.nameParent: del primSpec.nameParent.nameChildren[primSpec.name] else: del primSpec.nameRoot.nameChildren[primSpec.name] primSpec = Sdf.PrimSpec(schemaLayer, schemaName, Sdf.SpecifierClass, "" if isAPI else schemaName) primSpec.inheritPathList.explicitItems = ["/" + schemaBase] primSpecCustomData = {} if isAPI: primSpecCustomData["apiSchemaType"] = schemaKind if tfTypeNameSuffix: # Defines this classname for TfType system # can help avoid duplicate prefix with domain and className # Tf type system will automatically pick schemaName as tfTypeName if # this is not set! primSpecCustomData["className"] = tfTypeNameSuffix if apiSchemaAutoApplyTo: primSpecCustomData['apiSchemaAutoApplyTo'] = \ Vt.TokenArray(apiSchemaAutoApplyTo) primSpec.customData = primSpecCustomData doc = sdrNode.GetHelp() if doc != "": primSpec.documentation = doc # gather properties from node directly generated from USD (sourceType: USD) # Use the usdSchemaClass tag when the generated schema being defined is an # API schema usdSchemaNode = None if usdSchemaClass: reg = Sdr.Registry() usdSchemaNode = reg.GetNodeByIdentifierAndType( usdSchemaClass, SchemaDefiningMiscConstants.USD_SOURCE_TYPE) # Create attrSpecs from input parameters for propName in sdrNode.GetInputNames(): _CreateAttrSpecFromNodeAttribute(primSpec, sdrNode.GetInput(propName), usdSchemaNode) # Create attrSpecs from output parameters for propName in sdrNode.GetOutputNames(): _CreateAttrSpecFromNodeAttribute(primSpec, sdrNode.GetOutput(propName), usdSchemaNode, False) schemaLayer.Save()
def test_NodeDiscovery(self): """ Test MaterialX node discovery. """ # Let the plugin discover our nodes. searchPath = os.getcwd() os.environ['PXR_USDMTLX_PLUGIN_SEARCH_PATHS'] = searchPath registry = Sdr.Registry() # Check node indentifiers. names = sorted( registry.GetNodeIdentifiers('UsdMtlxTestNode', Ndr.VersionFilterAllVersions)) self.assertEqual(names, [ 'pxr_nd_float', 'pxr_nd_integer', 'pxr_nd_string', 'pxr_nd_vector', 'pxr_nd_vector_2', 'pxr_nd_vector_2_1', 'pxr_nd_vector_noversion' ]) # Check node names. names = sorted(registry.GetNodeNames('UsdMtlxTestNode')) self.assertEqual(names, [ 'pxr_nd_float', 'pxr_nd_integer', 'pxr_nd_string', 'pxr_nd_vector' ]) # Get by family. Non-default versions should be dropped. # # Because pxr_nd_vector_noversion has no version at all the # discovery assumes it's the default version despite appearances # to the human eye. nodes = registry.GetNodesByFamily('UsdMtlxTestNode') names = sorted([node.GetIdentifier() for node in nodes]) self.assertEqual(names, [ 'pxr_nd_float', 'pxr_nd_integer', 'pxr_nd_string', 'pxr_nd_vector_2', 'pxr_nd_vector_noversion' ]) # Check all versions. # Note that this sorting depends on how unique identifiers are # constructed so the order of items on the right hand side of # the assertion must stay in sync with that. names = sorted([ name for name in registry.GetNodeIdentifiers( filter=Ndr.VersionFilterAllVersions) if name.startswith('pxr_') ]) nodes = [registry.GetNodeByIdentifier(name) for name in names] versions = [node.GetVersion() for node in nodes] self.assertEqual(versions, [ Ndr.Version(), Ndr.Version(), Ndr.Version(), Ndr.Version(1), Ndr.Version(2, 0), Ndr.Version(2, 1), Ndr.Version() ]) # Check default versions. names = sorted([ name for name in registry.GetNodeIdentifiers( filter=Ndr.VersionFilterDefaultOnly) if name.startswith('pxr_') ]) self.assertEqual(names, [ 'pxr_nd_float', 'pxr_nd_integer', 'pxr_nd_string', 'pxr_nd_vector_2', 'pxr_nd_vector_noversion' ]) nodes = [registry.GetNodeByIdentifier(name) for name in names] versions = [node.GetVersion() for node in nodes] self.assertEqual(versions, [ Ndr.Version(), Ndr.Version(), Ndr.Version(), Ndr.Version(2, 0), Ndr.Version() ])
def test_NodeDiscovery(self): """ Test MaterialX node discovery. """ registry = Sdr.Registry() # Check node identifiers. names = sorted( registry.GetNodeIdentifiers('UsdMtlxTestNode', Ndr.VersionFilterAllVersions)) self.assertEqual(names, [ 'pxr_nd_boolean', 'pxr_nd_float', 'pxr_nd_integer', 'pxr_nd_string', 'pxr_nd_vector', 'pxr_nd_vector_2', 'pxr_nd_vector_2_1', 'pxr_nd_vector_noversion' ]) # Check node names. names = sorted(registry.GetNodeNames('UsdMtlxTestNode')) self.assertEqual(names, [ 'pxr_nd_boolean', 'pxr_nd_float', 'pxr_nd_integer', 'pxr_nd_string', 'pxr_nd_vector' ]) # Get by family. Non-default versions should be dropped. # # Because pxr_nd_vector_noversion has no version at all the # discovery assumes it's the default version despite appearances # to the human eye. nodes = registry.GetNodesByFamily('UsdMtlxTestNode') names = sorted([node.GetIdentifier() for node in nodes]) self.assertEqual(names, [ 'pxr_nd_boolean', 'pxr_nd_float', 'pxr_nd_integer', 'pxr_nd_string', 'pxr_nd_vector_2', 'pxr_nd_vector_noversion' ]) # Check all versions. # Note that this sorting depends on how unique identifiers are # constructed so the order of items on the right hand side of # the assertion must stay in sync with that. names = sorted([ name for name in registry.GetNodeIdentifiers( filter=Ndr.VersionFilterAllVersions) if name.startswith('pxr_') ]) nodes = [registry.GetNodeByIdentifier(name) for name in names] versions = [node.GetVersion() for node in nodes] self.assertEqual(versions, [ Ndr.Version(), Ndr.Version(), Ndr.Version(), Ndr.Version(), Ndr.Version(), Ndr.Version(1), Ndr.Version(2, 0), Ndr.Version(2, 1), Ndr.Version() ]) # Check default versions. names = sorted([ name for name in registry.GetNodeIdentifiers( filter=Ndr.VersionFilterDefaultOnly) if name.startswith('pxr_') ]) self.assertEqual(names, [ 'pxr_nd_boolean', 'pxr_nd_booleanDefaults', 'pxr_nd_float', 'pxr_nd_integer', 'pxr_nd_string', 'pxr_nd_vector_2', 'pxr_nd_vector_noversion' ]) nodes = [registry.GetNodeByIdentifier(name) for name in names] versions = [node.GetVersion() for node in nodes] self.assertEqual(versions, [ Ndr.Version(), Ndr.Version(), Ndr.Version(), Ndr.Version(), Ndr.Version(), Ndr.Version(2, 0), Ndr.Version() ]) # Check default values of boolean inputs: node = registry.GetNodeByIdentifier("pxr_nd_booleanDefaults") self.assertTrue(node) trueInput = node.GetInput("inTrue") self.assertTrue(trueInput.GetDefaultValue()) self.assertTrue(trueInput.GetDefaultValueAsSdfType()) falseInput = node.GetInput("inFalse") self.assertFalse(falseInput.GetDefaultValue()) self.assertFalse(falseInput.GetDefaultValueAsSdfType())
def test_SdrShaderNodesForLights(self): """ Test the automatic registration of SdrShaderNodes for all the UsdLux light types. """ # The expected shader node inputs that should be found for all of our # UsdLux light types. expectedLightInputNames = [ # LightAPI 'color', 'colorTemperature', 'diffuse', 'enableColorTemperature', 'exposure', 'intensity', 'normalize', 'specular', # ShadowAPI 'shadow:color', 'shadow:distance', 'shadow:enable', 'shadow:falloff', 'shadow:falloffGamma', # ShapingAPI 'shaping:cone:angle', 'shaping:cone:softness', 'shaping:focus', 'shaping:focusTint', 'shaping:ies:angleScale', 'shaping:ies:file', 'shaping:ies:normalize' ] # Map of the names of the expected light nodes to the additional inputs # we expect for those types. expectedLightNodes = { 'CylinderLight' : ['length', 'radius'], 'DiskLight' : ['radius'], 'DistantLight' : ['angle'], 'DomeLight' : ['texture:file', 'texture:format'], 'GeometryLight' : [], 'PortalLight' : [], 'RectLight' : ['width', 'height', 'texture:file'], 'SphereLight' : ['radius'], 'MeshLight' : [], 'VolumeLight' : [] } # Get all the derived types of UsdLuxBoundableLightBase and # UsdLuxNonboundableLightBase that are defined in UsdLux lightTypes = list(filter( Plug.Registry().GetPluginWithName("usdLux").DeclaresType, Tf.Type(UsdLux.BoundableLightBase).GetAllDerivedTypes() + Tf.Type(UsdLux.NonboundableLightBase).GetAllDerivedTypes())) self.assertTrue(lightTypes) # Augment lightTypes to include MeshLightAPI and VolumeLightAPI lightTypes.append( Tf.Type.FindByName('UsdLuxMeshLightAPI')) lightTypes.append( Tf.Type.FindByName('UsdLuxVolumeLightAPI')) # Verify that at least one known light type is in our list to guard # against this giving false positives if no light types are available. self.assertIn(UsdLux.RectLight, lightTypes) self.assertEqual(len(lightTypes), len(expectedLightNodes)) stage = Usd.Stage.CreateInMemory() prim = stage.DefinePrim("/Prim") usdSchemaReg = Usd.SchemaRegistry() for lightType in lightTypes: print("Test SdrNode for schema type " + str(lightType)) if usdSchemaReg.IsAppliedAPISchema(lightType): prim.ApplyAPI(lightType) else: typeName = usdSchemaReg.GetConcreteSchemaTypeName(lightType) if not typeName: continue prim.SetTypeName(typeName) light = UsdLux.LightAPI(prim) self.assertTrue(light) sdrIdentifier = light.GetShaderId([]) self.assertTrue(sdrIdentifier) prim.ApplyAPI(UsdLux.ShadowAPI) prim.ApplyAPI(UsdLux.ShapingAPI) # Every concrete light type and some API schemas (with appropriate # shaderId as sdr Identifier) in usdLux domain will have an # SdrShaderNode with source type 'USD' registered for it under its # USD schema type name. node = Sdr.Registry().GetNodeByIdentifier(sdrIdentifier, ['USD']) self.assertTrue(node is not None) self.assertIn(sdrIdentifier, expectedLightNodes) # Names, identifier, and role for the node all match the USD schema # type name self.assertEqual(node.GetIdentifier(), sdrIdentifier) self.assertEqual(node.GetName(), sdrIdentifier) self.assertEqual(node.GetImplementationName(), sdrIdentifier) self.assertEqual(node.GetRole(), sdrIdentifier) self.assertTrue(node.GetInfoString().startswith(sdrIdentifier)) # The context is always 'light' for lights. # Source type is 'USD' self.assertEqual(node.GetContext(), 'light') self.assertEqual(node.GetSourceType(), 'USD') # Help string is generated and encoded in the node's metadata (no # need to verify the specific wording). self.assertTrue(set(node.GetMetadata().keys()), {'primvars', 'help'}) self.assertEqual(node.GetMetadata()["help"], node.GetHelp()) # Source code and URIs are all empty. self.assertFalse(node.GetSourceCode()) self.assertFalse(node.GetResolvedDefinitionURI()) self.assertFalse(node.GetResolvedImplementationURI()) # Other classifications are left empty. self.assertFalse(node.GetCategory()) self.assertFalse(node.GetDepartments()) self.assertFalse(node.GetFamily()) self.assertFalse(node.GetLabel()) self.assertFalse(node.GetVersion()) self.assertFalse(node.GetAllVstructNames()) self.assertEqual(node.GetPages(), ['']) # The node will be valid for our light types. self.assertTrue(node.IsValid()) # Helper for comparing an SdrShaderProperty from node to the # corresponding UsdShadeInput/UsdShadeOutput from a UsdLux light def _CompareLightPropToNodeProp(nodeInput, primInput): # Input names and default values match. primDefaultValue = primInput.GetAttr().Get() self.assertEqual(nodeInput.GetName(), primInput.GetBaseName()) self.assertEqual(nodeInput.GetDefaultValue(), primDefaultValue) # Some USD property types don't match exactly one to one and are # converted to different types. In particular relevance to # lights and Token becomes String. expectedTypeName = primInput.GetTypeName() # Array valued attributes have their array size determined from # the default value and will be converted to scalar in the # SdrProperty if the array size is zero. if expectedTypeName.isArray: if not primDefaultValue or len(primDefaultValue) == 0: expectedTypeName = expectedTypeName.scalarType elif expectedTypeName == Sdf.ValueTypeNames.Token: expectedTypeName = Sdf.ValueTypeNames.String # Bool SdfTypes should Have Int SdrTypes, but still return as # Bool when queried for GetTypeAsSdfType if expectedTypeName == Sdf.ValueTypeNames.Bool: self.assertEqual(nodeInput.GetType(), Sdf.ValueTypeNames.Int) # Verify the node's input type maps back to USD property's type # (with the noted above exceptions). self.assertEqual( nodeInput.GetTypeAsSdfType()[0], expectedTypeName, msg="{}.{} Type {} != {}".format( str(node.GetName()), str(nodeInput.GetName()), str(nodeInput.GetTypeAsSdfType()[0]), str(expectedTypeName))) # If the USD property type is an Asset, it will be listed in # the node's asset identifier inputs. if expectedTypeName == Sdf.ValueTypeNames.Asset: self.assertIn(nodeInput.GetName(), node.GetAssetIdentifierInputNames()) # There will be a one to one correspondence between node inputs # and prim inputs. Note that the prim may have additional inputs # because of auto applied API schemas, but we only need to verify # that the node has ONLY the expected inputs and the prim at least # has those input proerties. expectedInputNames = \ expectedLightInputNames + expectedLightNodes[sdrIdentifier] # Verify node has exactly the expected inputs. self.assertEqual(sorted(expectedInputNames), sorted(node.GetInputNames())) # Verify each node input matches a prim input. for inputName in expectedInputNames: nodeInput = node.GetInput(inputName) primInput = light.GetInput(inputName) self.assertFalse(nodeInput.IsOutput()) _CompareLightPropToNodeProp(nodeInput, primInput) # None of the UsdLux base lights have outputs self.assertEqual(node.GetOutputNames(), []) self.assertEqual(light.GetOutputs(onlyAuthored=False), []) # The reverse is tested just above, but for all asset identifier # inputs listed for the node there is a corresponding asset value # input property on the prim. for inputName in node.GetAssetIdentifierInputNames(): self.assertEqual(light.GetInput(inputName).GetTypeName(), Sdf.ValueTypeNames.Asset) # These primvars come from sdrMetadata on the prim itself which # isn't supported for light schemas so it will always be empty. self.assertFalse(node.GetPrimvars()) # sdrMetadata on input properties is supported so additional # primvar properties will correspond to prim inputs with that # metadata set. for propName in node.GetAdditionalPrimvarProperties(): self.assertTrue(light.GetInput(propName).GetSdrMetadataByKey( 'primvarProperty')) # Default input can also be specified in the property's sdrMetadata. if node.GetDefaultInput(): defaultInput = light.GetInput( node.GetDefaultInput().GetName()) self.assertTrue(defaultInput.GetSdrMetadataByKey('defaultInput'))
def UpdateSchemaWithSdrNode(schemaLayer, sdrNode, renderContext="", overrideIdentifier=""): """ Updates the given schemaLayer with primSpec and propertySpecs from sdrNode metadata. A renderContext can be provided which is used in determining the shaderId namespace, which follows the pattern: "<renderContext>:<SdrShaderNodeContext>:shaderId". Note that we are using a node's context (SDR_NODE_CONTEXT_TOKENS) here to construct the shaderId namespace, so shader parsers should make sure to use appropriate SDR_NODE_CONTEXT_TOKENS in the node definitions. overrideIdentifier parameter is the identifier which should be used when the identifier of the node being processed differs from the one Sdr will discover at runtime, such as when this function is def a node constructed from an explicit asset path. This should only be used when clients know the identifier being passed is the true identifier which sdr Runtime will provide when querying using GetShaderNodeByNameAndType, etc. It consumes the following attributes (that manifest as Sdr metadata) in addition to many of the standard Sdr metadata specified and parsed (via its parser plugin). Node Level Metadata: - "schemaName": Name of the new schema populated from the given sdrNode (Required) - "schemaKind": Specifies the UsdSchemaKind for the schema being populated from the sdrNode. (Note that this does not support multiple apply schema kinds). - "schemaBase": Base schema from which the new schema should inherit from. Note this defaults to "APISchemaBase" for an API schema or "Typed" for a concrete scheme. - "usdSchemaClass": Specifies the equivalent schema directly generated by USD (sourceType: USD). This is used to make sure duplicate properties already specified in the USD schema are not populated in the new API schema. Note this is only used when we are dealing with an API schema. - "apiSchemaAutoApplyTo": The schemas to which the sdrNode populated API schema will autoApply to. - "apiSchemaCanOnlyApplyTo": If specified, the API schema generated from the sdrNode can only be validly applied to this set of schemas. - "providesUsdShadeConnectableAPIBehavior": Used to enable a connectability behavior for an API schema. - "isUsdShadeContainer": Only used when providesUsdShadeConnectableAPIBehavior is set to true. Marks the connectable prim as a UsdShade container type. - "requiresUsdShadeEncapsulation": Only used when providesUsdShadeConnectableAPIBehavior is set to true. Configures the UsdShade encapsulation rules governing its connectableBehavior. - "tfTypeNameSuffix": Class name which will get registered with TfType system. This gets appended to the domain name to register with TfType. Property Level Metadata: - USD_VARIABILITY: Property level metadata which specifies a specific sdrNodeProperty should have its USD variability set to Uniform or Varying - USD_SUPPRESS_PROPERTY: A property level metadata which determines if the property should be suppressed from translation from args to property spec. Sdr Property Metadata to SdfPropertySpec Translations - A "null" value for Widget sdrProperty metadata translates to SdfPropertySpec Hidden metadata. - SdrProperty's Help metadata (Label metadata if Help metadata not provided) translates to SdfPropertySpec's Documentation string metadata. - SdrProperty's Page metadata translates to SdfPropertySpec's DisplayGroup metadata. - SdrProperty's Label metadata translates to SdfPropertySpec's DisplayName metadata. - SdrProperty's Options translates to SdfPropertySpec's AllowedTokens. - SdrProperty's Default value translates to SdfPropertySpec's Default value. - Connectable input properties translates to InterfaceOnly SdfPropertySpec's CONNECTABILITY. """ import distutils.util import os # Early exit on invalid parameters if not schemaLayer: Tf.Warn("No Schema Layer provided") return if not sdrNode: Tf.Warn("No valid sdrNode provided") return sdrNodeMetadata = sdrNode.GetMetadata() if SchemaDefiningKeys.SCHEMA_NAME not in sdrNodeMetadata: Tf.Warn("Sdr Node (%s) does not define a schema name metadata." \ %(sdrNode.GetName())) return schemaName = sdrNodeMetadata[SchemaDefiningKeys.SCHEMA_NAME] if not Tf.IsValidIdentifier(schemaName): Tf.RaiseRuntimeError( "schemaName (%s) is an invalid identifier; " "Provide a valid USD identifer for schemaName, example (%s) " % (schemaName, Tf.MakeValidIdentifier(schemaName))) tfTypeNameSuffix = None if SchemaDefiningKeys.TF_TYPENAME_SUFFIX in sdrNodeMetadata: tfTypeNameSuffix = sdrNodeMetadata[ SchemaDefiningKeys.TF_TYPENAME_SUFFIX] if not Tf.IsValidIdentifier(tfTypeNameSuffix): Tf.RaiseRuntimeError("tfTypeNameSuffix (%s) is an invalid " \ "identifier" %(tfTypeNameSuffix)) if SchemaDefiningKeys.SCHEMA_KIND not in sdrNodeMetadata: schemaKind = SchemaDefiningMiscConstants.TYPED_SCHEMA else: schemaKind = sdrNodeMetadata[SchemaDefiningKeys.SCHEMA_KIND] # Note: We are not working on dynamic multiple apply schemas right now. isAPI = schemaKind == SchemaDefiningMiscConstants.SINGLE_APPLY_SCHEMA # Fix schemaName and warn if needed if isAPI and \ not schemaName.endswith(SchemaDefiningMiscConstants.API_STRING): Tf.Warn("node metadata implies the generated schema being created is " "an API schema, fixing schemaName to reflect that") schemaName = schemaName + SchemaDefiningMiscConstants.API_STRING if isAPI and tfTypeNameSuffix and \ not tfTypeNameSuffix.endswith(SchemaDefiningMiscConstants.API_STRING): Tf.Warn("node metadata implies the generated schema being created " "is an API schema, fixing tfTypeNameSuffix to reflect that") tfTypeNameSuffix = tfTypeNameSuffix + \ SchemaDefiningMiscConstants.API_STRING if SchemaDefiningKeys.SCHEMA_BASE not in sdrNodeMetadata: Tf.Warn("No schemaBase specified in node metadata, defaulting to " "APISchemaBase for API schemas else Typed") schemaBase = SchemaDefiningMiscConstants.API_SCHEMA_BASE if isAPI \ else SchemaDefiningMiscConstants.TYPED_SCHEMA else: schemaBase = sdrNodeMetadata[SchemaDefiningKeys.SCHEMA_BASE] apiSchemaAutoApplyTo = None if SchemaDefiningKeys.API_SCHEMA_AUTO_APPLY_TO in sdrNodeMetadata: apiSchemaAutoApplyTo = \ sdrNodeMetadata[SchemaDefiningKeys.API_SCHEMA_AUTO_APPLY_TO] \ .split('|') apiSchemaCanOnlyApplyTo = None if SchemaDefiningKeys.API_SCHEMA_CAN_ONLY_APPLY_TO in sdrNodeMetadata: apiSchemaCanOnlyApplyTo = \ sdrNodeMetadata[SchemaDefiningKeys.API_SCHEMA_CAN_ONLY_APPLY_TO] \ .split('|') providesUsdShadeConnectableAPIBehavior = False if SchemaDefiningKeys.PROVIDES_USD_SHADE_CONNECTABLE_API_BEHAVIOR in \ sdrNodeMetadata: providesUsdShadeConnectableAPIBehavior = \ distutils.util.strtobool(sdrNodeMetadata[SchemaDefiningKeys. \ PROVIDES_USD_SHADE_CONNECTABLE_API_BEHAVIOR]) usdSchemaClass = None if isAPI and SchemaDefiningKeys.USD_SCHEMA_CLASS in sdrNodeMetadata: usdSchemaClass = \ sdrNodeMetadata[SchemaDefiningKeys.USD_SCHEMA_CLASS] primSpec = schemaLayer.GetPrimAtPath(schemaName) if (primSpec): # if primSpec already exist, remove entirely and recreate using the # parsed sdr node if primSpec.nameParent: del primSpec.nameParent.nameChildren[primSpec.name] else: del primSpec.nameRoot.nameChildren[primSpec.name] primSpec = Sdf.PrimSpec(schemaLayer, schemaName, Sdf.SpecifierClass, "" if isAPI else schemaName) primSpec.inheritPathList.explicitItems = ["/" + schemaBase] primSpecCustomData = {} if isAPI: primSpecCustomData["apiSchemaType"] = schemaKind if tfTypeNameSuffix: # Defines this classname for TfType system # can help avoid duplicate prefix with domain and className # Tf type system will automatically pick schemaName as tfTypeName if # this is not set! primSpecCustomData["className"] = tfTypeNameSuffix if apiSchemaAutoApplyTo: primSpecCustomData['apiSchemaAutoApplyTo'] = \ Vt.TokenArray(apiSchemaAutoApplyTo) if apiSchemaCanOnlyApplyTo: primSpecCustomData['apiSchemaCanOnlyApplyTo'] = \ Vt.TokenArray(apiSchemaCanOnlyApplyTo) if providesUsdShadeConnectableAPIBehavior: extraPlugInfo = { SchemaDefiningKeys.PROVIDES_USD_SHADE_CONNECTABLE_API_BEHAVIOR \ : True } for propKey in [SchemaDefiningKeys.IS_USD_SHADE_CONTAINER, \ SchemaDefiningKeys.REQUIRES_USD_SHADE_ENCAPSULATION]: if propKey in sdrNodeMetadata: # Since we want to assign the types for these to bool and # because in python boolean type is a subset of int, we need to # do following instead of assign the propValue directly. propValue = distutils.util.strtobool(sdrNodeMetadata[propKey]) extraPlugInfo[propKey] = bool(propValue) primSpecCustomData['extraPlugInfo'] = extraPlugInfo primSpec.customData = primSpecCustomData doc = sdrNode.GetHelp() if doc != "": primSpec.documentation = doc # gather properties from node directly generated from USD (sourceType: USD) # Use the usdSchemaClass tag when the generated schema being defined is an # API schema usdSchemaNode = None if usdSchemaClass: reg = Sdr.Registry() if usdSchemaClass.endswith(SchemaDefiningMiscConstants.API_STRING): # This usd schema is an API schema, we need to extract the shader # identifier from its primDef's shaderId field. primDef = Usd.SchemaRegistry().FindAppliedAPIPrimDefinition( usdSchemaClass) if primDef: # We are dealing with USD source type here, hence no render # context is required but we can still borrow node context # information from the sdrNode in question, since the usd source # type node should also belong to the same context. shaderIdAttrName = Sdf.Path.JoinIdentifier( \ sdrNode.GetContext(), PropertyDefiningKeys.SHADER_ID) sdrIdentifier = primDef.GetAttributeFallbackValue( shaderIdAttrName) if sdrIdentifier != "": usdSchemaNode = reg.GetNodeByIdentifierAndType( sdrIdentifier, SchemaDefiningMiscConstants.USD_SOURCE_TYPE) else: Tf.Warn("No sourceId authored for '%s'." % (usdSchemaClass)) else: Tf.Warn("Illegal API schema provided for the usdSchemaClass " "metadata. No prim definition registered for '%s'" % (usdSchemaClass)) else: usdSchemaNode = reg.GetNodeByIdentifierAndType( usdSchemaClass, SchemaDefiningMiscConstants.USD_SOURCE_TYPE) # Create attrSpecs from input parameters for propName in sdrNode.GetInputNames(): _CreateAttrSpecFromNodeAttribute(primSpec, sdrNode.GetInput(propName), usdSchemaNode) # Create attrSpecs from output parameters for propName in sdrNode.GetOutputNames(): _CreateAttrSpecFromNodeAttribute(primSpec, sdrNode.GetOutput(propName), usdSchemaNode, False) # Create token shaderId attrSpec shaderIdAttrName = Sdf.Path.JoinIdentifier( \ [renderContext, sdrNode.GetContext(), PropertyDefiningKeys.SHADER_ID]) shaderIdAttrSpec = Sdf.AttributeSpec(primSpec, shaderIdAttrName, Sdf.ValueTypeNames.Token, Sdf.VariabilityUniform) # Since users shouldn't need to be aware of shaderId attribute, we put this # in "Internal" displayGroup. shaderIdAttrSpec.displayGroup = PropertyDefiningKeys.INTERNAL_DISPLAY_GROUP # Use the identifier if explicitly provided, (it could be a shader node # queried using an explicit path), else use sdrNode's registered identifier. nodeIdentifier = overrideIdentifier if overrideIdentifier else \ sdrNode.GetIdentifier() shaderIdAttrSpec.default = nodeIdentifier # Extra attrSpec schemaBasePrimDefinition = \ Usd.SchemaRegistry().FindConcretePrimDefinition(schemaBase) if schemaBasePrimDefinition and \ SchemaDefiningMiscConstants.NodeDefAPI in \ schemaBasePrimDefinition.GetAppliedAPISchemas(): infoIdAttrSpec = Sdf.AttributeSpec(primSpec, \ UsdShade.Tokens.infoId, Sdf.ValueTypeNames.Token, \ Sdf.VariabilityUniform) infoIdAttrSpec.default = nodeIdentifier schemaLayer.Save()
def test_SdrShaderNodesForLights(self): """ Test the automatic registration of SdrShaderNodes for all the UsdLux light types. """ # Get all the derived types of UsdLuxLight lightTypes = Tf.Type(UsdLux.Light).GetAllDerivedTypes() self.assertTrue(lightTypes) # Verify that at least one known light type is in our list to guard # against this giving false positives if no light types are available. self.assertIn(UsdLux.RectLight, lightTypes) stage = Usd.Stage.CreateInMemory() prim = stage.DefinePrim("/Prim") for lightType in lightTypes: # Every concrete light type will have an SdrShaderNode with source # type 'USD' registered for it under its USD schema type name. typeName = Usd.SchemaRegistry.GetConcreteSchemaTypeName(lightType) node = Sdr.Registry().GetNodeByName(typeName, ['USD']) self.assertTrue(node.IsValid()) # Set the prim to the light type so we can cross check node inputs # with the light prim built-in properties. prim.SetTypeName(typeName) light = UsdLux.Light(prim) self.assertTrue(light) # Names, identifier, and role for the node all match the USD schema # type name self.assertEqual(node.GetIdentifier(), typeName) self.assertEqual(node.GetName(), typeName) self.assertEqual(node.GetImplementationName(), typeName) self.assertEqual(node.GetRole(), typeName) self.assertTrue(node.GetInfoString().startswith(typeName)) # The context is always 'light'. Source type is 'USD' self.assertEqual(node.GetContext(), 'light') self.assertEqual(node.GetSourceType(), 'USD') # Help string is generated and encoded in the node's metadata (no # need to verify the specific wording). self.assertTrue(set(node.GetMetadata().keys()), {'primvars', 'help'}) self.assertEqual(node.GetMetadata()["help"], node.GetHelp()) # Source code and URIs are all empty. self.assertFalse(node.GetSourceCode()) self.assertFalse(node.GetResolvedDefinitionURI()) self.assertFalse(node.GetResolvedImplementationURI()) # Other classifications are left empty. self.assertFalse(node.GetCategory()) self.assertFalse(node.GetDepartments()) self.assertFalse(node.GetFamily()) self.assertFalse(node.GetLabel()) self.assertFalse(node.GetVersion()) self.assertFalse(node.GetAllVstructNames()) self.assertEqual(node.GetPages(), ['']) # Helper for comparing an SdrShaderProperty from node to the # corresponding UsdShadeInput/UsdShadeOutput from a UsdLuxLight def _CompareLightPropToNodeProp(nodeInput, lightInput): # Input names and default values match. self.assertEqual(nodeInput.GetName(), lightInput.GetBaseName()) self.assertEqual(nodeInput.GetDefaultValue(), lightInput.GetAttr().Get()) # Some USD property types don't match exactly one to one and are # converted to different types. In particular relevance to # lights, Bool becomes Int and Token becomes String. expectedTypeName = lightInput.GetTypeName() if expectedTypeName == Sdf.ValueTypeNames.Bool: expectedTypeName = Sdf.ValueTypeNames.Int elif expectedTypeName == Sdf.ValueTypeNames.Token: expectedTypeName = Sdf.ValueTypeNames.String # Verify the node's input type maps back to USD property's type # (with the noted above exceptions). self.assertEqual( nodeInput.GetTypeAsSdfType()[0], expectedTypeName, msg="Type {} != {}".format( str(nodeInput.GetTypeAsSdfType()[0]), str(expectedTypeName))) # If the USD property type is an Asset, it will be listed in # the node's asset indentifier inputs. if expectedTypeName == Sdf.ValueTypeNames.Asset: self.assertIn(nodeInput.GetName(), node.GetAssetIdentifierInputNames()) # There will be a one to one correspondence between node inputs # and light prim inputs. nodeInputs = [node.GetInput(i) for i in node.GetInputNames()] lightInputs = light.GetInputs() for nodeInput, lightInput in zip(nodeInputs, lightInputs): self.assertFalse(nodeInput.IsOutput()) _CompareLightPropToNodeProp(nodeInput, lightInput) # There will also be a one to one correspondence between node # outputs and light prim outputs. nodeOutputs = [node.GetOutput(i) for i in node.GetOutputNames()] lightOutputs = light.GetOutputs() for nodeOutput, lightOutput in zip(nodeOutputs, lightOutputs): self.assertTrue(nodeOutput.IsOutput()) _CompareLightPropToNodeProp(nodeOutput, lightOutput) # The reverse is tested just above, but for all asset identifier # inputs listed for the node there is a corresponding asset value # input property on the light prim. for inputName in node.GetAssetIdentifierInputNames(): self.assertEqual(light.GetInput(inputName).GetTypeName(), Sdf.ValueTypeNames.Asset) # These primvars come from sdrMetadata on the prim itself which # isn't supported for light schemas so it will alwasy be empty. self.assertFalse(node.GetPrimvars()) # sdrMetadata on input properties is supported so additional # primvar properties will correspond to light inputs with that # metadata set. for propName in node.GetAdditionalPrimvarProperties(): self.assertTrue(light.GetInput(propName).GetSdrMetadataByKey( 'primvarProperty')) # Default input can also be specified in the property's sdrMetadata. if node.GetDefaultInput(): defaultLightInput = light.GetInput( node.GetDefaultInput().GetName()) self.assertTrue(lightInput.GetSdrMetadataByKey('defaultInput'))