def read_usd_material(cls, material, texture_path, time=None): r"""Read USD material and return a Material object. The shader used must have a corresponding registered reader function. If no available reader is found, the material parameters will be returned as a dictionary. Args: material (UsdShade.Material): Valid USD Material prim texture_path (str, optional): Path to textures directory. If the USD has absolute paths to textures, set to an empty string. By default, the textures will be assumed to be under the same directory as the USD specified by `file_path`. time (convertible to float, optional): Positive integer indicating the time at which to retrieve parameters. Returns: (Material): Material object determined by the corresponding reader function. """ if time is None: time = Usd.TimeCode.Default() if not UsdShade.Material(material): raise MaterialLoadError( f'The material `{material}` is not a valid UsdShade.Material object.' ) for surface_output in material.GetSurfaceOutputs(): if not surface_output.HasConnectedSource(): continue surface_shader = surface_output.GetConnectedSource()[0] shader = UsdShade.Shader(surface_shader) if not UsdShade.Shader(shader): raise MaterialLoadError( f'The shader `{shader}` is not a valid UsdShade.Shader object.' ) if shader.GetImplementationSourceAttr().Get(time=time) == 'id': shader_name = UsdShade.Shader(surface_shader).GetShaderId() elif shader.GetPrim().HasAttribute('info:mdl:sourceAsset'): # source_asset = shader.GetPrim().GetAttribute('info:mdl:sourceAsset').Get(time=time) shader_name = shader.GetPrim().GetAttribute( 'info:mdl:sourceAsset:subIdentifier').Get(time=time) else: shader_name = '' warnings.warn( f'A reader for the material defined by `{material}` is not yet implemented.' ) params = _get_shader_parameters(surface_shader, time) if shader_name not in cls._usd_readers: warnings.warn( 'No registered readers were able to process the material ' f'`{material}` with shader `{shader_name}`.') return params reader = cls._usd_readers[shader_name] return reader(params, texture_path, time) raise MaterialError(f'Error processing material {material}')
def IsConverter(self): mtlxShaderReaderTest.IsConverterCalled = True self._refinedOutputToken = '' prim = self._GetArgs().GetUsdPrim() shaderSchema = UsdShade.Shader(prim) if (not shaderSchema): return None shaderId = shaderSchema.GetIdAttr().Get() input = shaderSchema.GetInput('in') if (not input): return None (source, sourceOutputName, sourceType) = input.GetConnectedSource() if (not source): return None downstreamSchema = UsdShade.Shader(source.GetPrim()) if (not downstreamSchema): return None # No refinement necessary for ND_convert_color3_vector3 and ND_normalmap. if ("ND_luminance_" in shaderId): # Luminance is an alpha output. self._setAlphaIsLuminance = True self._refinedOutputToken = 'outAlpha' elif ("ND_swizzle_" in shaderId): channelsAttr = shaderSchema.GetInput('channels') val = channelsAttr.Get(Usd.TimeCode.Default()) if (val == 'r' or val == 'x'): self._refinedOutputToken = 'outColorR' elif (val == 'g'): self._refinedOutputToken = 'outColorG' elif (val == 'y'): if (shaderSchema.GetOutput('out').GetTypeName() == 'Float'): self._refinedOutputToken = 'outAlpha' else: self._refinedOutputToken = 'outColorG' elif (val == 'b' or val == 'z'): self._refinedOutputToken = 'outColorB' elif (val == 'a' or val == 'w'): self._refinedOutputToken = 'outAlpha' else: print("Unsupported swizzle" + val) # TF_CODING_ERROR("Unsupported swizzle"); # } else if (channels.size() == 3) { # // Triple channel swizzles must go to outColor: # self._refinedOutputToken = 'outColor'; # } self._downstreamPrim = source.GetPrim() return downstreamSchema, sourceOutputName
def testExportPxrRisShading(self): """ Tests that exporting a Maya mesh with a simple Maya shading setup results in the correct shading on the USD mesh. """ cubePrim = self._stage.GetPrimAtPath('/MarbleCube/Geom/Cube') self.assertTrue(cubePrim) # Validate the Material prim bound to the Mesh prim. materialBindingAPI = UsdShade.MaterialBindingAPI(cubePrim) material = materialBindingAPI.ComputeBoundMaterial()[0] self.assertTrue(material) materialPath = material.GetPath().pathString self.assertEqual(materialPath, '/MarbleCube/Materials/MarbleCubeSG') if Usd.GetVersion() >= (0, 21, 5): # For USD 21.05 and later, GetInputs() and GetOutputs() take an # "onlyAuthored" argument that is True by default, so in that case # we expect only one output on the material for the "surface" # terminal in the "ri" renderContext that the export should have # authored. expectedNumOutputs = 1 else: # Otherwise prior to USD 21.05, GetInputs() and GetOutputs() did # not take any arguments and always included the built-in # terminals for the universal renderContext as well as any other # authored terminals. expectedNumOutputs = 4 # Validate the surface shader that is connected to the material. materialOutputs = material.GetOutputs() self.assertEqual(len(materialOutputs), expectedNumOutputs) print(self._stage.ExportToString()) materialOutput = material.GetOutput('ri:surface') (connectableAPI, outputName, outputType) = materialOutput.GetConnectedSource() self.assertEqual(outputName, 'out') shader = UsdShade.Shader(connectableAPI) self.assertTrue(shader) shaderId = shader.GetIdAttr().Get() self.assertEqual(shaderId, 'PxrMayaMarble') # Validate the connected input on the surface shader. shaderInput = shader.GetInput('placementMatrix') self.assertTrue(shaderInput) (connectableAPI, outputName, outputType) = shaderInput.GetConnectedSource() self.assertEqual(outputName, 'worldInverseMatrix') shader = UsdShade.Shader(connectableAPI) self.assertTrue(shader) shaderId = shader.GetIdAttr().Get() self.assertEqual(shaderId, 'PxrMayaPlacement3d')
def testExportPxrRisShading(self): """ Tests that exporting a Maya mesh with a simple Maya shading setup results in the correct shading on the USD mesh. """ cubePrim = self._stage.GetPrimAtPath('/MarbleCube/Geom/Cube') self.assertTrue(cubePrim) # Validate the Material prim bound to the Mesh prim. material = UsdShade.Material.GetBoundMaterial(cubePrim) self.assertTrue(material) materialPath = material.GetPath().pathString self.assertEqual(materialPath, '/MarbleCube/Looks/MarbleCubeSG') # Validate the surface shader that is connected to the material. # XXX: Note that the expected number of outputs here is two rather than # one, since we are still authoring the UsdRi Bxdf source in addition # to the surface terminal for backwards compatibility. When consumers # are updated to use the surface terminal instead, this test will have # to be updated. materialOutputs = material.GetOutputs() self.assertEqual(len(materialOutputs), 2) materialOutput = material.GetOutput('surface') (connectableAPI, outputName, outputType) = materialOutput.GetConnectedSource() self.assertEqual(outputName, 'out') shader = UsdShade.Shader(connectableAPI) self.assertTrue(shader) # XXX: Validate the UsdRi Bxdf. This must also be removed when we no # longer author it. from pxr import UsdRi usdRiMaterialAPI = UsdRi.MaterialAPI(material.GetPrim()) self.assertTrue(usdRiMaterialAPI) bxdf = usdRiMaterialAPI.GetBxdf() self.assertEqual(bxdf.GetPrim(), shader.GetPrim()) shaderId = shader.GetIdAttr().Get() self.assertEqual(shaderId, 'PxrMayaMarble') # Validate the connected input on the surface shader. shaderInput = shader.GetInput('placementMatrix') self.assertTrue(shaderInput) (connectableAPI, outputName, outputType) = shaderInput.GetConnectedSource() self.assertEqual(outputName, 'worldInverseMatrix') shader = UsdShade.Shader(connectableAPI) self.assertTrue(shader) shaderId = shader.GetIdAttr().Get() self.assertEqual(shaderId, 'PxrMayaPlacement3d')
def testExportRfMShaders(self): ''' Tests that exporting a Maya mesh with a simple Maya shading setup results in the correct shading on the USD mesh. ''' cubePrim = self._stage.GetPrimAtPath('/MarbleCube/Geom/Cube') self.assertTrue(cubePrim) # Validate the Material prim bound to the Mesh prim. self.assertTrue(cubePrim.HasAPI(UsdShade.MaterialBindingAPI)) materialBindingAPI = UsdShade.MaterialBindingAPI(cubePrim) material = materialBindingAPI.ComputeBoundMaterial()[0] self.assertTrue(material) materialPath = material.GetPath().pathString self.assertEqual(materialPath, '/MarbleCube/Materials/MarbleCubeSG') # We expect four outputs on the material, the three built-in terminals # for the universal renderContext, and a fourth for the "surface" # terminal in the "ri" renderContext that the export should have # authored. materialOutputs = material.GetOutputs() self.assertEqual(len(materialOutputs), 4) # Validate the lambert surface shader that is connected to the material. materialOutput = material.GetOutput('ri:surface') (connectableAPI, outputName, outputType) = materialOutput.GetConnectedSource() self.assertEqual(outputName, UsdShade.Tokens.surface) shader = UsdShade.Shader(connectableAPI) self.assertTrue(shader) shaderId = shader.GetIdAttr().Get() self.assertEqual(shaderId, 'PxrMayaLambert') # Validate the connected input on the lambert surface shader. shaderInput = shader.GetInput('color') self.assertTrue(shaderInput) (connectableAPI, outputName, outputType) = shaderInput.GetConnectedSource() self.assertEqual(outputName, 'outColor') shader = UsdShade.Shader(connectableAPI) self.assertTrue(shader) shaderId = shader.GetIdAttr().Get() self.assertEqual(shaderId, 'PxrMayaMarble') # Validate the connected input on the marble shader. shaderInput = shader.GetInput('placementMatrix') self.assertTrue(shaderInput) (connectableAPI, outputName, outputType) = shaderInput.GetConnectedSource() self.assertEqual(outputName, 'worldInverseMatrix') shader = UsdShade.Shader(connectableAPI) self.assertTrue(shader) shaderId = shader.GetIdAttr().Get() self.assertEqual(shaderId, 'PxrMayaPlacement3d')
def testExportDisplacementShaders(self): ''' Tests that exporting multiple Maya planes with varying displacement setups results in the expected USD data: ''' textures = ["RGBA", "RGB", "MonoA", "Mono"] channels = ["r", "g", "b", "a", "a"] for suffix in range(1, 21): image = textures[int((suffix - 1) / 5)] channel = channels[(suffix - 1) % 5] mesh_prim = self._stage.GetPrimAtPath('/pPlane%i' % suffix) self.assertTrue(mesh_prim) # Validate the Material prim bound to the Mesh prim. self.assertTrue(mesh_prim.HasAPI(UsdShade.MaterialBindingAPI)) mat_binding = UsdShade.MaterialBindingAPI(mesh_prim) material = mat_binding.ComputeBoundMaterial()[0] self.assertTrue(material) material_path = material.GetPath().pathString self.assertEqual( material_path, '/pPlane%i/Materials/blinn%iSG' % (suffix, suffix)) self.assertTrue(material.ComputeSurfaceSource()) self.assertTrue(material.ComputeDisplacementSource()) # Validate the shader that is connected to the material. mat_out = material.GetOutput(UsdShade.Tokens.displacement) (connect_api, out_name, _) = mat_out.GetConnectedSource() self.assertEqual(out_name, UsdShade.Tokens.displacement) shader = UsdShade.Shader(connect_api) self.assertTrue(shader) shader_id = shader.GetIdAttr().Get() self.assertEqual(shader_id, 'UsdPreviewSurface') # Validate the connected input on the displacement shader. in_displacement = shader.GetInput('displacement') self.assertTrue(in_displacement) (connect_api, out_name, _) = in_displacement.GetConnectedSource() self.assertEqual(out_name, channel) shader = UsdShade.Shader(connect_api) self.assertTrue(shader) shader_id = shader.GetIdAttr().Get() self.assertEqual(shader_id, 'UsdUVTexture') filename = shader.GetInput("file") self.assertTrue(filename.Get().path.endswith("/%s.png" % image))
def _TestShading(self, stage, materialsPath): ConnAPI = UsdShade.ConnectableAPI # Create parent material parentMaterialPath = materialsPath.AppendChild('ParentMaterial') parentMaterial = UsdShade.Material.Define(stage, parentMaterialPath) floatInterfaceInput = parentMaterial.CreateInput( 'floatVal', Sdf.ValueTypeNames.Float) parentShader1 = UsdShade.Shader.Define( stage, parentMaterialPath.AppendChild("Shader_1")) floatShaderInput = parentShader1.CreateInput('floatInput', Sdf.ValueTypeNames.Float) floatShaderInput.Set(1.0) parentShader2 = UsdShade.Shader.Define( stage, parentMaterialPath.AppendChild("Shader_2")) floatShaderOutput = parentShader2.CreateOutput( 'floatOutput', Sdf.ValueTypeNames.Float) self.assertTrue( ConnAPI.ConnectToSource(floatShaderInput, floatShaderOutput)) print(stage.GetRootLayer().ExportToString()) print(ConnAPI.GetConnectedSources(floatShaderInput)) self.assertTrue(ConnAPI.HasConnectedSource(floatShaderInput)) self.assertFalse( ConnAPI.IsSourceConnectionFromBaseMaterial(floatShaderInput)) self.assertTrue(not parentMaterial.HasBaseMaterial()) # Create child materials # one with SetBaseMaterial childMaterials = [] childMaterialPath = materialsPath.AppendChild('ChildMaterial_1') childMaterial = UsdShade.Material.Define(stage, childMaterialPath) childMaterial.SetBaseMaterial(parentMaterial) childMaterials.append(childMaterial) # one with SetBaseMaterialPath childMaterialPath = materialsPath.AppendChild('ChildMaterial_2') childMaterial = UsdShade.Material.Define(stage, childMaterialPath) childMaterial.SetBaseMaterialPath(parentMaterialPath) childMaterials.append(childMaterial) # verify that material is found for childMaterial in childMaterials: self.assertTrue(childMaterial.HasBaseMaterial()) self.assertEqual(childMaterial.GetBaseMaterialPath(), parentMaterialPath) childShaderPath = childMaterial.GetPrim().GetPath().AppendChild( "Shader_1") childShaderPrim = stage.GetPrimAtPath(childShaderPath) # verify that inheritance is found and resolved self.assertEqual(bool(childShaderPrim), True) childShader = UsdShade.Shader(childShaderPrim) self.assertTrue(childShader) childShaderInput = childShader.GetInput('floatInput') self.assertEqual(childShaderInput.GetAttr().Get(), 1.0) self.assertTrue( ConnAPI.IsSourceConnectionFromBaseMaterial(childShaderInput))
def testExportUDIM(self): ''' Tests that exporting a UDIM texture works: ''' maya_file = os.path.join(self.test_dir, 'UsdExportUDIMTest.ma') cmds.file(maya_file, force=True, open=True) # Export to USD. usd_file = os.path.abspath('UsdExportUDIMTest.usda') cmds.mayaUSDExport(mergeTransformAndShape=True, file=usd_file, shadingMode='useRegistry', convertMaterialsTo=['UsdPreviewSurface'], materialsScopeName='Materials') stage = Usd.Stage.Open(usd_file) self.assertTrue(stage) shader_prim = stage.GetPrimAtPath( '/pPlane1/Materials/lambert2SG/file1') self.assertTrue(shader_prim) shader = UsdShade.Shader(shader_prim) shader_id = shader.GetIdAttr().Get() self.assertEqual(shader_id, 'UsdUVTexture') filename = shader.GetInput("file") self.assertTrue("<UDIM>" in filename.Get().path)
def _CheckShader(self, prim): from pxr import Sdf, UsdShade self._Msg("Checking shader <%s>." % prim.GetPath()) shader = UsdShade.Shader(prim) if not shader: self._AddError("Prim <%s> with typename 'Shader' is not a valid " "shader." % prim.GetPath(), ruleNum=8) return implSource = shader.GetImplementationSource() if implSource != UsdShade.Tokens.id: self._AddFailedCheck("Shader <%s> has non-id implementation " "source '%s'." % (prim.GetPath(), implSource), ruleNum=8) shaderId = shader.GetShaderId() if not shaderId or not shaderId.startswith('Usd'): self._AddFailedCheck("Shader <%s> has unsupported info:id '%s'." % (prim.GetPath(), shaderId), ruleNum=8) shaderInputs = shader.GetInputs() for ip in shaderInputs: if ip.GetTypeName() == Sdf.ValueTypeNames.Asset: texFilePath = str(ip.Get()).strip('@') self._CheckTexture(texFilePath) elif ip.GetTypeName() == Sdf.ValueTypeNames.AssetArray: texPathArray = ip.Get() texPathArray = [str(i).strip('@') for i in texPathArray] for texPath in texPathArray: self._CheckTexture(texFilePath)
def testShaderAttrsAuthoredSparsely(self): """ Tests that only the attributes authored in Maya are exported to USD. """ shaderPrimPath = '/MarbleCube/Looks/MarbleCubeSG/MarbleShader' shaderPrim = self._stage.GetPrimAtPath(shaderPrimPath) self.assertTrue(shaderPrim) shader = UsdShade.Shader(shaderPrim) self.assertTrue(shader) shaderId = shader.GetIdAttr().Get() self.assertEqual(shaderId, 'PxrMayaMarble') shaderInputs = shader.GetInputs() self.assertEqual(len(shaderInputs), 3) inputOutAlpha = shader.GetInput('outAlpha').Get() self.assertTrue(Gf.IsClose(inputOutAlpha, 0.0894, 1e-6)) inputOutColor = shader.GetInput('outColor').Get() self.assertTrue(Gf.IsClose(inputOutColor, Gf.Vec3f(0.298, 0.0, 0.0), 1e-6)) inputPlacementMatrix = shader.GetInput('placementMatrix') (connectableAPI, outputName, outputType) = inputPlacementMatrix.GetConnectedSource() self.assertEqual(connectableAPI.GetPath().pathString, '/MarbleCube/Looks/MarbleCubeSG/MarbleCubePlace3dTexture') shaderOutputs = shader.GetOutputs() self.assertEqual(len(shaderOutputs), 1)
def testExportedUsdShadeNodeTypes(self): ''' Tests that all node ids are what we expect: ''' base_path = "/pCube{0}/Materials/{1}SG/{2}/{1}" to_test = [ # pCube1 has standard_surface, known to UsdPreviewSurface and MaterialX (1, "standardSurface2", "UsdPreviewSurface", "UsdPreviewSurface"), (1, "standardSurface2", "MaterialX", "ND_standard_surface_surfaceshader"), # pCube2 has lambert, known to UsdPreviewSurface and RfM (2, "lambert2", "UsdPreviewSurface", "UsdPreviewSurface"), (2, "lambert2", "rendermanForMaya", "PxrMayaLambert"), # pCube3 has UsdPreviewSurface, known to UsdPreviewSurface and MaterialX (3, "usdPreviewSurface1", "UsdPreviewSurface", "UsdPreviewSurface"), (3, "usdPreviewSurface1", "MaterialX", "ND_UsdPreviewSurface_surfaceshader"), ] for prim_idx, shd_name, shd_scope, id_attr in to_test: prim_path = base_path.format(prim_idx, shd_name, shd_scope) prim = self._stage.GetPrimAtPath(prim_path) self.assertTrue(prim, prim_path) shader = UsdShade.Shader(prim) self.assertTrue(shader, prim_path) self.assertEqual(shader.GetIdAttr().Get(), id_attr)
def testUsdExportCustomConverter(self): """ Tests a custom exporter for a conversion that exists in an unloaded plugin. """ # Load test scene: file_path = os.path.join(self.input_path, "UsdExportCustomConverterTest", "testScene.ma") cmds.file(file_path, force=True, open=True) # Export to USD: usd_path = os.path.abspath('UsdExportCustomConverterTest.usda') # Using the "maya" material conversion, which only exists in the test # plugin options = ["shadingMode=useRegistry", "convertMaterialsTo=maya", "mergeTransformAndShape=1"] default_ext_setting = cmds.file(q=True, defaultExtensions=True) cmds.file(defaultExtensions=False) cmds.file(usd_path, force=True, options=";".join(options), typ="USD Export", pr=True, ea=True) cmds.file(defaultExtensions=default_ext_setting) # Make sure we have a Maya standardSurface material in the USD file: stage = Usd.Stage.Open(usd_path) material = stage.GetPrimAtPath( "/pCube1/Looks/standardSurface2SG/standardSurface2") shader = UsdShade.Shader(material) self.assertEqual(shader.GetIdAttr().Get(), "standardSurface")
def testExportSelfContainedPackage(self): """ Tests that the exported usdz file is self contained, such that it's valid for AR QuickLook on iOS """ maya_file = os.path.join(self.temp_dir, "UsdExportPackage", "asset.ma") cmds.file(maya_file, force=True, open=True) # Write the file out path = os.path.join(self.temp_dir, 'testExportSelfContainedPackage.usdz') cmds.mayaUSDExport(f=path, compatibility='appleArKit') # Check with USD what the path to the texture is stage = Usd.Stage.Open(path) prim = stage.GetPrimAtPath( "/AssetGroup/Looks/pxrUsdPreviewSurface1SG/file1") shader = UsdShade.Shader(prim) tex = shader.GetInput("file").Get().path # Check to see if the zipfile contains the texture with zipfile.ZipFile(path) as zf: for zfile in zf.filelist: if zfile.filename == tex: break else: self.fail("Could not find texture inside zip file")
def testExportStandaloneTransform2dTransformed(self): """ Test that a material with transform 2D values exports with a UsdTransform2D shader and the correct values """ root = self.stage.GetPrimAtPath( "/PxrUsdTransform2dExportTest/Looks/pxrUsdPreviewSurface_TransformedSG" ) transform = findTransformPrim(root) self.assertTrue(transform, "Missing UsdTransform2D shader") shader = UsdShade.Shader(transform) translation_input = shader.GetInput('translation') rotation_input = shader.GetInput('rotation') scale_input = shader.GetInput('scale') expected_translation_value = (0.10104963, 0.19860554) expected_rotation_value = 0.2 expected_scale_value = (0.8, 1) self.assertAlmostEqual(translation_input.Get(), expected_translation_value) self.assertAlmostEqual(rotation_input.Get(), expected_rotation_value) self.assertEqual(scale_input.Get(), expected_scale_value)
def CheckPrim(self, prim): # Right now, we find texture referenced by looking at the asset-valued # shader inputs. However, it is entirely legal to feed the "fileName" # input of a UsdUVTexture shader from a UsdPrimvarReader_string. # Hence, ideally we would also check "the right" primvars on # geometry prims here. However, identifying the right primvars is # non-trivial. We probably need to pre-analyze all the materials. # Not going to try to do this yet, but it raises an interesting # validation pattern - from pxr import Sdf, UsdShade # Check if the prim is a shader. if not prim.IsA(UsdShade.Shader): return shader = UsdShade.Shader(prim) shaderInputs = shader.GetInputs() for ip in shaderInputs: if ip.GetTypeName() == Sdf.ValueTypeNames.Asset: texFilePath = str(ip.Get()).strip('@') self._CheckTexture(texFilePath) elif ip.GetTypeName() == Sdf.ValueTypeNames.AssetArray: texPathArray = ip.Get() texPathArray = [str(i).strip('@') for i in texPathArray] for texPath in texPathArray: self._CheckTexture(texFilePath)
def testShaderAttrsAuthoredSparsely(self): """ Tests that only the attributes authored in Maya are exported to USD. """ shaderPrimPath = '/MarbleCube/Materials/MarbleCubeSG/MarbleShader' shaderPrim = self._stage.GetPrimAtPath(shaderPrimPath) self.assertTrue(shaderPrim) shader = UsdShade.Shader(shaderPrim) self.assertTrue(shader) shaderId = shader.GetIdAttr().Get() self.assertEqual(shaderId, 'PxrMayaMarble') shaderInputs = shader.GetInputs() self.assertEqual(len(shaderInputs), 1) inputPlacementMatrix = shader.GetInput('placementMatrix') (connectableAPI, outputName, outputType) = inputPlacementMatrix.GetConnectedSource() self.assertEqual( connectableAPI.GetPath().pathString, '/MarbleCube/Materials/MarbleCubeSG/MarbleCubePlace3dTexture') shaderOutputs = shader.GetOutputs() self.assertEqual(len(shaderOutputs), 1)
def _AddShadingToBall(stage): from pxr import Sdf, UsdShade model = stage.OverridePrim('/Ball') texDir = os.path.join(ASSET_BASE, 'Ball/tex') mesh = stage.OverridePrim('/Ball/mesh') ballTexture = UsdShade.Shader( stage.OverridePrim( model.GetPath().AppendPath('Looks/BallMaterial/BallTexture'))) # now we'll show adding some shading variants to the ball as well. shadingVariantsInfo = [ ('Cue', '', _Color(0.996, 0.992, 0.874)), # white ('Ball_1', '', _Color(1.000, 0.929, 0.184)), # yellow ('Ball_2', '', _Color(0.157, 0.243, 0.631)), # blue ('Ball_3', '', _Color(0.976, 0.212, 0.141)), # red ('Ball_4', '', _Color(0.250, 0.156, 0.400)), # purple ('Ball_5', '', _Color(0.980, 0.498, 0.184)), # orange ('Ball_6', '', _Color(0.050, 0.255, 0.239)), # green ('Ball_7', '', _Color(0.607, 0.059, 0.094)), # darkred ('Ball_8', '', _Color(0.122, 0.118, 0.110)), # black ('Ball_9', 'striped', _Color(1.000, 0.929, 0.184)), # yellow ('Ball_10', 'striped', _Color(0.157, 0.243, 0.631)), # blue ('Ball_11', 'striped', _Color(0.976, 0.212, 0.141)), # red ('Ball_12', 'striped', _Color(0.250, 0.156, 0.400)), # purple ('Ball_13', 'striped', _Color(0.980, 0.498, 0.184)), # orange ('Ball_14', 'striped', _Color(0.050, 0.255, 0.239)), # green ('Ball_15', 'striped', _Color(0.607, 0.059, 0.094)), # darkred ] # create the shadingVariant variantSet shadingVariant = model.GetVariantSets().AddVariantSet('shadingVariant') for variantName, decoration, color in shadingVariantsInfo: # creates a variant inside 'shadingVariant' shadingVariant.AddVariant(variantName) # switch to that variant shadingVariant.SetVariantSelection(variantName) # this 'with' construct here tells Usd that authoring operations should # write to the shadingVariant. with shadingVariant.GetVariantEditContext(): whichBall = variantName.split('_')[-1] texPath = os.path.join(texDir, 'ball%s.tex' % whichBall) # in the current variant, modify the color _SetParameters(ballTexture, [ ('filename', Sdf.ValueTypeNames.String, texPath), ]) # set the display color for hydra _SetDisplayColor(mesh, color) # currently not doing anything with decoration, but we could maybe # use this to make the solid vs. stripes. # now make the variant selection 'Cue' instead of the last variant that we # created above. shadingVariant.SetVariantSelection('Cue')
def _GetSourceShader(self, inputOrOutput): (connectableAPI, _, _) = inputOrOutput.GetConnectedSource() self.assertTrue(connectableAPI.IsShader()) shaderPrim = connectableAPI.GetPrim() self.assertTrue(shaderPrim) shader = UsdShade.Shader(shaderPrim) self.assertTrue(shader) return shader
def CheckPrim(self, prim): from pxr import UsdShade if not prim.IsA(UsdShade.Shader): return shader = UsdShade.Shader(prim) if not shader: # Error has already been issued by a Base-level checker return self._Msg("Checking shader <%s>." % prim.GetPath()) implSource = shader.GetImplementationSource() if implSource != UsdShade.Tokens.id: self._AddFailedCheck("Shader <%s> has non-id implementation " "source '%s'." % (prim.GetPath(), implSource)) shaderId = shader.GetShaderId() if not shaderId or \ not (shaderId in [NodeTypes.UsdPreviewSurface, NodeTypes.UsdUVTexture, NodeTypes.UsdTransform2d] or shaderId.startswith(NodeTypes.UsdPrimvarReader)) : self._AddFailedCheck("Shader <%s> has unsupported info:id '%s'." % (prim.GetPath(), shaderId)) # Check shader input connections shaderInputs = shader.GetInputs() for shdInput in shaderInputs: connections = shdInput.GetAttr().GetConnections() # If an input has one or more connections, ensure that the # connections are valid. if len(connections) > 0: if len(connections) > 1: self._AddFailedCheck( "Shader input <%s> has %s connection " "sources, but only one is allowed." % (shdInput.GetAttr.GetPath(), len(connections))) connectedSource = shdInput.GetConnectedSource() if connectedSource is None: self._AddFailedCheck( "Connection source <%s> for shader " "input <%s> is missing." % (connections[0], shdInput.GetAttr().GetPath())) else: # The source must be a valid shader or material prim. source = connectedSource[0] if not source.GetPrim().IsA(UsdShade.Shader) and \ not source.GetPrim().IsA(UsdShade.Material): self._AddFailedCheck( "Shader input <%s> has an invalid " "connection source prim of type '%s'." % (shdInput.GetAttr().GetPath(), source.GetPrim().GetTypeName()))
def testExportPxrRisShading(self): """ Tests that exporting a Maya mesh with a simple Maya shading setup results in the correct shading on the USD mesh. """ cubePrim = self._stage.GetPrimAtPath('/MarbleCube/Geom/Cube') self.assertTrue(cubePrim) # Validate the Material prim bound to the Mesh prim. materialBindingAPI = UsdShade.MaterialBindingAPI(cubePrim) material = materialBindingAPI.ComputeBoundMaterial()[0] self.assertTrue(material) materialPath = material.GetPath().pathString self.assertEqual(materialPath, '/MarbleCube/Materials/MarbleCubeSG') # Validate the surface shader that is connected to the material. materialOutputs = material.GetOutputs() self.assertEqual(len(materialOutputs), 4) print self._stage.ExportToString() materialOutput = material.GetOutput('ri:surface') (connectableAPI, outputName, outputType) = materialOutput.GetConnectedSource() self.assertEqual(outputName, 'out') shader = UsdShade.Shader(connectableAPI) self.assertTrue(shader) shaderId = shader.GetIdAttr().Get() self.assertEqual(shaderId, 'PxrMayaMarble') # Validate the connected input on the surface shader. shaderInput = shader.GetInput('placementMatrix') self.assertTrue(shaderInput) (connectableAPI, outputName, outputType) = shaderInput.GetConnectedSource() self.assertEqual(outputName, 'worldInverseMatrix') shader = UsdShade.Shader(connectableAPI) self.assertTrue(shader) shaderId = shader.GetIdAttr().Get() self.assertEqual(shaderId, 'PxrMayaPlacement3d')
def testShaderAttrsAuthoredSparsely(self): ''' Tests that only the attributes authored in Maya are exported to USD. ''' shaderPrimPath = '/MarbleCube/Materials/MarbleCubeSG/MarbleLambert' shaderPrim = self._stage.GetPrimAtPath(shaderPrimPath) self.assertTrue(shaderPrim) shader = UsdShade.Shader(shaderPrim) self.assertTrue(shader) shaderId = shader.GetIdAttr().Get() self.assertEqual(shaderId, 'PxrMayaLambert') shaderInputs = shader.GetInputs() self.assertEqual(len(shaderInputs), 1) # We actually expect two outputs on the "top-level" shader. The Maya # node this shader came from would have had an "outColor" output that # should have been translated, and then a "surface" output should have # been created when the shader was bound into the Material. shaderOutputs = shader.GetOutputs() self.assertEqual(len(shaderOutputs), 2) outputNames = {o.GetBaseName() for o in shaderOutputs} self.assertEqual(outputNames, set(['outColor', 'surface'])) # Traverse the network down to the marble shader shaderInput = shader.GetInput('color') self.assertTrue(shaderInput) (connectableAPI, outputName, outputType) = shaderInput.GetConnectedSource() shader = UsdShade.Shader(connectableAPI) self.assertTrue(shader) inputPlacementMatrix = shader.GetInput('placementMatrix') (connectableAPI, outputName, outputType) = inputPlacementMatrix.GetConnectedSource() self.assertEqual( connectableAPI.GetPath().pathString, '/MarbleCube/Materials/MarbleCubeSG/MarbleCubePlace3dTexture') shaderId = shader.GetIdAttr().Get() self.assertEqual(shaderId, 'PxrMayaMarble') shaderOutputs = shader.GetOutputs() self.assertEqual(len(shaderOutputs), 1)
def findTransformPrim(root): for prim in root.GetAllChildren(): if not prim.IsA(UsdShade.Shader): continue shader = UsdShade.Shader(prim) shader_type = shader.GetIdAttr().Get() if shader_type == "UsdTransform2d": return prim transform = findTransformPrim(prim) if transform: return transform
def read_from_usd(self, file_path, scene_path, texture_path=None, time=None): r"""Read material from USD. Args: file_path (str): Path to usd file (\*.usd, \*.usda). scene_path (str): Absolute path of UsdShade.Material prim within the USD file scene. Must be a valid ``Sdf.Path``. texture_path (str, optional): Path to textures directory. If the USD has absolute paths to textures, set to an empty string. By default, the textures will be assumed to be under the same directory as the USD specified by `file_path`. time (convertible to float, optional): Positive integer indicating the time at which to retrieve parameters. """ if time is None: time = Usd.TimeCode.Default() if texture_path is None: texture_file_path = os.path.dirname(file_path) else: usd_dir = os.path.dirname(file_path) texture_file_path = posixpath.join(usd_dir, texture_path) stage = Usd.Stage.Open(file_path) material = UsdShade.Material(stage.GetPrimAtPath(scene_path)) assert material surface_shader = material.GetSurfaceOutput().GetConnectedSource()[0] shader = UsdShade.Shader(surface_shader) if shader.GetImplementationSourceAttr().Get(time=time) == 'id': shader_name = UsdShade.Shader(surface_shader).GetShaderId() else: raise NotImplementedError material_params = _get_shader_parameters(surface_shader, time) reader = self.shaders[shader_name]['reader'] return reader(material_params, texture_file_path, time)
def _SetupStage(self): stage = Usd.Stage.CreateInMemory() UsdGeom.Scope.Define(stage, "/Model") UsdGeom.Scope.Define(stage, "/Model/Materials") UsdShade.Material.Define(stage, "/Model/Materials/MaterialSharp") pale = UsdShade.Shader.Define(stage, palePath) self.assertTrue(pale) whiterPale = UsdShade.Shader.Define(stage, whiterPalePath) self.assertTrue(whiterPale) # Make a class for pale so we can test that disconnecting/blocking works classPale = stage.CreateClassPrim(classPalePath) self.assertTrue(classPale) pale.GetPrim().GetInherits().AppendInherit(classPalePath) shaderClass = UsdShade.Shader(classPale) # it's not valid because it's not defined, but we can still author using it self.assertTrue(not shaderClass) return stage
def testPythonCustomShaderExporter(self): ''' Add a custom exporter to the mix and see if it can export a compositing node. ''' cmds.file(f=True, new=True) # Register our new exporter: mayaUsdLib.ShaderWriter.Register(mxCompositeExportTest, "colorComposite") mayaFile = os.path.join(self._inputPath, 'UsdExportMaterialXTest', 'MaterialX_decal.ma') cmds.file(mayaFile, force=True, open=True) # Export to USD. usdFilePath = os.path.abspath('MaterialX_decal.usda') cmds.mayaUSDExport(mergeTransformAndShape=True, file=usdFilePath, shadingMode='useRegistry', convertMaterialsTo=['MaterialX'], materialsScopeName='Materials') stage = Usd.Stage.Open(usdFilePath) self.assertTrue(stage) # We should have a nice colorComposite1 node in the graph curtesy of the custom exporter: prim = stage.GetPrimAtPath("/pPlane1/Materials/standardSurface2SG/MayaNG_standardSurface2SG/colorComposite1") self.assertTrue(prim) shader = UsdShade.Shader(prim) self.assertTrue(shader) self.assertEqual(shader.GetIdAttr().Get(), "ND_mix_color3") input = shader.GetInput("fg") self.assertEqual(input.Get(), (1,1,0)) input = shader.GetInput("bg") cnxTuple = input.GetConnectedSource() self.assertTrue(cnxTuple) self.assertEqual(cnxTuple[0].GetPrim().GetName(), "file1") input = shader.GetInput("mix") cnxTuple = input.GetConnectedSource() self.assertTrue(cnxTuple) self.assertEqual(cnxTuple[0].GetPrim().GetName(), "MayaSwizzle_file2_a") self.assertTrue("MaterialX" in mxCompositeExportTest._AllMaterialConversions)
def testExportTexturedMaterialXpPlane1(self): ''' Tests that pPlane1 exported as planned: this plane is a basic RGB texture without any customizations. ''' cmds.file(f=True, new=True) mayaFile = os.path.join(self._inputPath, 'UsdExportMaterialXTest', 'StandardSurfaceTextured.ma') cmds.file(mayaFile, force=True, open=True) # Export to USD. usdFilePath = os.path.abspath('UsdExportMaterialXTest.usda') cmds.mayaUSDExport(mergeTransformAndShape=True, file=usdFilePath, shadingMode='useRegistry', convertMaterialsTo=['MaterialX'], materialsScopeName='Materials') stage = Usd.Stage.Open(usdFilePath) self.assertTrue(stage) # Exploring this path: base_path = "/pPlane1/Materials/standardSurface2SG" mesh_prim = stage.GetPrimAtPath('/pPlane1') self.assertTrue(mesh_prim) # Validate the Material prim bound to the Mesh prim. self.assertTrue(mesh_prim.HasAPI(UsdShade.MaterialBindingAPI)) mat_binding = UsdShade.MaterialBindingAPI(mesh_prim) mat = mat_binding.ComputeBoundMaterial("mtlx")[0] self.assertTrue(mat) material_path = mat.GetPath().pathString self.assertEqual(material_path, base_path) # Needs a resolved inputs:file1:varnameStr attribute: self.assertEqual(mat.GetInput("file1:varnameStr").GetAttr().Get(), "st") # Needs a MaterialX surface source: shader = mat.ComputeSurfaceSource("mtlx")[0] self.assertTrue(shader) # Which is a standard surface: self.assertEqual(shader.GetIdAttr().Get(), "ND_standard_surface_surfaceshader") # With a connected file texture on base_color going to baseColor on the # nodegraph: attr = shader.GetInput('base_color') self.assertTrue(attr) cnxTuple = attr.GetConnectedSource() self.assertTrue(cnxTuple) ng_path = base_path + '/MayaNG_standardSurface2SG' ng = UsdShade.NodeGraph(cnxTuple[0]) self.assertEqual(ng.GetPath(), ng_path) self.assertEqual(cnxTuple[1], "baseColor") # Should have an outputs connected to a file node: attr = ng.GetOutput('baseColor') self.assertTrue(attr) cnxTuple = attr.GetConnectedSource() self.assertTrue(cnxTuple) # Which is a color3 image: shader = UsdShade.Shader(cnxTuple[0]) self.assertEqual(shader.GetIdAttr().Get(), "ND_image_color3") self.assertEqual(shader.GetPath(), ng_path + "/file1") # Check a few values: self.assertTrue(self.compareValue(shader, "uaddressmode", "periodic")) self.assertTrue(self.compareValue(shader, "default", (0.5, 0.5, 0.5))) # Which is itself connected to a primvar reader: attr = shader.GetInput('texcoord') self.assertTrue(attr) cnxTuple = attr.GetConnectedSource() self.assertTrue(cnxTuple) # Which is a geompropvalue node: shader = UsdShade.Shader(cnxTuple[0]) self.assertEqual(shader.GetIdAttr().Get(), "ND_geompropvalue_vector2") self.assertEqual(shader.GetPath(), ng_path + "/place2dTexture1") base_path = "/pPlane{0}/Materials/standardSurface{1}SG/MayaNG_standardSurface{1}SG/{2}" to_test = [ (7, 8, "file7", "ND_image_float"), (6, 7, "file6", "ND_image_vector2"), (1, 2, "file1", "ND_image_color3"), (4, 5, "file4", "ND_image_color4"), (1, 2, "place2dTexture1", "ND_geompropvalue_vector2"), (4, 5, "MayaSwizzle_file4_rgb", "ND_swizzle_color4_color3"), (6, 7, "MayaSwizzle_file6_xxx", "ND_swizzle_vector2_color3"), (19, 21, "MayaSwizzle_file20_x", "ND_swizzle_vector2_float"), (7, 8, "MayaSwizzle_file7_rrr", "ND_swizzle_float_color3"), (8, 9, "MayaSwizzle_file8_r", "ND_swizzle_color4_float"), (13, 14, "MayaSwizzle_file13_g", "ND_swizzle_color3_float"), (27, 20, "MayaLuminance_file27", "ND_luminance_color3"), (12, 13, "MayaLuminance_file12", "ND_luminance_color4"), (14, 15, "MayaConvert_file14_color3f_float3", "ND_convert_color3_vector3"), (15, 16, "MayaNormalMap_standardSurface16_normalCamera", "ND_normalmap"), ] for prim_idx, sg_idx, node_name, id_attr in to_test: prim_path = base_path.format(prim_idx, sg_idx, node_name) prim = stage.GetPrimAtPath(prim_path) self.assertTrue(prim, prim_path) shader = UsdShade.Shader(prim) self.assertTrue(shader, prim_path) self.assertEqual(shader.GetIdAttr().Get(), id_attr, id_attr)
def convert_to_usd(gltf_file, usd_file, fps, scale, arkit=False, verbose=False, use_euler_rotation=False, optimize_textures=False, generate_texture_transform_texture=True, scale_texture=False): """Converts a glTF file to USD Arguments: gltf_file {str} -- path to glTF file usd_file {str} -- path to write USD file Keyword Arguments: verbose {bool} -- [description] (default: {False}) """ temp_dir = tempfile.mkdtemp() temp_usd_file = os.path.join(temp_dir, ntpath.basename(usd_file)) try: usd = GLTF2USD(gltf_file=gltf_file, usd_file=temp_usd_file, fps=fps, scale=scale, verbose=verbose, use_euler_rotation=use_euler_rotation, optimize_textures=optimize_textures, generate_texture_transform_texture= generate_texture_transform_texture, scale_texture=scale_texture) if usd.stage: asset = usd.stage.GetRootLayer() gltf_asset = usd.gltf_loader.get_asset() if gltf_asset: gltf_metadata = {'creator': 'gltf2usd v{}'.format(__version__)} if gltf_asset.generator: gltf_metadata['gltf_generator'] = gltf_asset.generator if gltf_asset.version: gltf_metadata['gltf_version'] = gltf_asset.version if gltf_asset.minversion: gltf_metadata['gltf_minversion'] = gltf_asset.minversion if gltf_asset.copyright: gltf_metadata['gltf_copyright'] = gltf_asset.copyright if gltf_asset.extras: for key, value in gltf_asset.extras.items(): gltf_metadata['gltf_extras_{}'.format(key)] = value asset.customLayerData = gltf_metadata usd.logger.info('Conversion complete!') asset.Save() usd.logger.info('created {}'.format(asset.realPath)) if not os.path.isdir(os.path.dirname(usd_file)): os.makedirs(os.path.dirname(usd_file)) if temp_usd_file.endswith('.usdz') or temp_usd_file.endswith( '.usdc'): usdc_file = '%s.%s' % (os.path.splitext(temp_usd_file)[0], 'usdc') asset.Export(usdc_file, args=dict(format='usdc')) usd.logger.info('created {}'.format(usdc_file)) if temp_usd_file.endswith('.usdz'): #change to directory of the generated usd files to avoid issues with # relative paths with CreateNewUsdzPackage os.chdir(os.path.dirname(usdc_file)) temp_usd_file = ntpath.basename(temp_usd_file) r = Ar.GetResolver() resolved_asset = r.Resolve(ntpath.basename(usdc_file)) context = r.CreateDefaultContextForAsset(resolved_asset) success = check_usd_compliance(resolved_asset, arkit=args.arkit) with Ar.ResolverContextBinder(context): if arkit and not success: usd.logger.warning('USD is not ARKit compliant') return success = UsdUtils.CreateNewUsdzPackage( resolved_asset, temp_usd_file) and success if success: shutil.copyfile(temp_usd_file, usd_file) usd.logger.info( 'created package {} with contents:'.format( usd_file)) zip_file = Usd.ZipFile.Open(usd_file) file_names = zip_file.GetFileNames() for file_name in file_names: usd.logger.info('\t{}'.format(file_name)) else: usd.logger.error( 'could not create {}'.format(usd_file)) else: # Copy textures referenced in the Usda/Usdc files from the temp directory to the target directory temp_stage = Usd.Stage.Open(temp_usd_file) usd_uv_textures = [ x for x in temp_stage.Traverse() if x.IsA(UsdShade.Shader) and UsdShade.Shader(x).GetShaderId() == 'UsdUVTexture' ] for usd_uv_texture in usd_uv_textures: file_name = usd_uv_texture.GetAttribute( 'inputs:file').Get() if file_name: file_name = str(file_name).replace('@', '') if os.path.isfile(os.path.join(temp_dir, file_name)): shutil.copyfile( os.path.join(temp_dir, file_name), os.path.join(os.path.dirname(usd_file), file_name)) shutil.copyfile(temp_usd_file, usd_file) finally: shutil.rmtree(temp_dir)
def CheckPrim(self, prim): from pxr import UsdShade, Gf from pxr.UsdShade import Utils as ShadeUtils if not prim.IsA(UsdShade.Shader): return shader = UsdShade.Shader(prim) if not shader: self._AddError("Invalid shader prim <%s>." % prim.GetPath()) return shaderId = self._GetShaderId(shader) # We may have failed to fetch an identifier for asset/source-based # nodes. We are only interested in UsdPreviewSurface nodes identified via # info:id, so it's not an error if not shaderId or shaderId != NodeTypes.UsdPreviewSurface: return normalInput = shader.GetInput(ShaderProps.Normal) if not normalInput: return valueProducingAttrs = ShadeUtils.GetValueProducingAttributes( normalInput) if not valueProducingAttrs or valueProducingAttrs[0].GetPrim() == prim: return sourcePrim = valueProducingAttrs[0].GetPrim() sourceShader = UsdShade.Shader(sourcePrim) if not sourceShader: # In theory, could be connected to an interface attribute of a # parent connectable... not useful, but not an error if UsdShade.ConnectableAPI(sourcePrim): return self._AddFailedCheck("%s.%s on prim <%s> is connected to a" " non-Shader prim." % \ (NodeTypes.UsdPreviewSurface, ShaderProps.Normal)) return sourceId = self._GetShaderId(sourceShader) # We may have failed to fetch an identifier for asset/source-based # nodes. OR, we could potentially be driven by a UsdPrimvarReader, # in which case we'd have nothing to validate if not sourceId or sourceId != NodeTypes.UsdUVTexture: return texAsset = self._GetInputValue(sourceShader, ShaderProps.File) if not texAsset or not texAsset.resolvedPath: self._AddFailedCheck("%s prim <%s> has invalid or unresolvable " "inputs:file of @%s@" % \ (NodeTypes.UsdUVTexture, sourcePrim.GetPath(), texAsset.path if texAsset else "")) return if not self._TextureIs8Bit(texAsset): # really nothing more is required for image depths > 8 bits, # which we assume FOR NOW, are floating point return if not self._GetInputValue(sourceShader, ShaderProps.SourceColorSpace): self._AddWarning("%s prim <%s> that reads Normal Map @%s@ may need " "to set inputs:sourceColorSpace to 'raw' as some " "8-bit image writers always indicate an SRGB " "encoding." % \ (NodeTypes.UsdUVTexture, sourcePrim.GetPath(), texAsset.path)) bias = self._GetInputValue(sourceShader, ShaderProps.Bias) scale = self._GetInputValue(sourceShader, ShaderProps.Scale) if not (bias and scale and isinstance(bias, Gf.Vec4f) and isinstance(scale, Gf.Vec4f)): # XXX This should be a failure, as it results in broken normal # maps in Storm and hdPrman, at least. But for the same reason # as the shader-under-shader check, we cannot fail until at least # the major authoring tools have been updated. self._AddWarning("%s prim <%s> reads 8 bit Normal Map @%s@, " "which requires that inputs:scale be set to " "[2, 2, 2, 1] and inputs:bias be set to " "[-1, -1, -1, 0] for proper interpretation." %\ (NodeTypes.UsdUVTexture, sourcePrim.GetPath(), texAsset.path)) return # don't really care about fourth components... if (bias[0] != -1 or bias[1] != -1 or bias[2] != -1 or scale[0] != 2 or scale[1] != 2 or scale[2] != 2): self._AddWarning("%s prim <%s> reads an 8 bit Normal Map, " "but has non-standard inputs:scale and " "inputs:bias values of %s and %s" %\ (NodeTypes.UsdUVTexture, sourcePrim.GetPath(), str(scale), str(bias)))
def testExportDisplayColorShading(self): """ Tests that exporting a Maya mesh with a simple Maya shading setup results in the correct shading on the USD mesh. """ # Validate the displayColor on the mesh prim. cubePrim = self._stage.GetPrimAtPath('/RedCube/Geom/Cube') self.assertTrue(cubePrim) cubeMesh = UsdGeom.Mesh(cubePrim) self.assertTrue(cubeMesh) meshDisplayColors = cubeMesh.GetDisplayColorPrimvar().Get() self.assertEqual(len(meshDisplayColors), 1) self.assertTrue(Gf.IsClose(meshDisplayColors[0], self.RED_COLOR, 1e-6)) # Validate the Material prim bound to the Mesh prim. material = UsdShade.Material.GetBoundMaterial(cubePrim) self.assertTrue(material) materialPath = material.GetPath().pathString self.assertEqual(materialPath, '/RedCube/Looks/RedLambertSG') materialInputs = material.GetInputs() self.assertEqual(len(materialInputs), 3) materialInput = material.GetInput('displayColor') matDisplayColor = materialInput.Get() self.assertTrue(Gf.IsClose(matDisplayColor, self.RED_COLOR, 1e-6)) # Just verify that displayOpacity and transparency exist. materialInput = material.GetInput('displayOpacity') self.assertTrue(materialInput) materialInput = material.GetInput('transparency') self.assertTrue(materialInput) # Validate the surface shader that is connected to the material. materialOutputs = material.GetOutputs() self.assertEqual(len(materialOutputs), 4) print(self._stage.ExportToString()) materialOutput = material.GetOutput('ri:surface') (connectableAPI, outputName, outputType) = materialOutput.GetConnectedSource() self.assertEqual(outputName, 'out') shader = UsdShade.Shader(connectableAPI) self.assertTrue(shader) self.assertEqual(shader.GetPrim().GetName(), 'RedLambertSG_lambert') shaderId = shader.GetIdAttr().Get() self.assertEqual(shaderId, 'PxrDiffuse') shaderInputs = shader.GetInputs() self.assertEqual(len(shaderInputs), 2) diffuseInput = shader.GetInput('diffuseColor') self.assertTrue(diffuseInput) (connectableAPI, outputName, outputType) = diffuseInput.GetConnectedSource() self.assertEqual(outputName, 'displayColor') self.assertTrue(connectableAPI) self.assertEqual(connectableAPI.GetPath().pathString, materialPath) transmissionInput = shader.GetInput('transmissionColor') self.assertTrue(transmissionInput) (connectableAPI, outputName, outputType) = transmissionInput.GetConnectedSource() self.assertEqual(outputName, 'transparency') self.assertTrue(connectableAPI) self.assertEqual(connectableAPI.GetPath().pathString, materialPath)
def testExportDisplayColorShading(self): """ Tests that exporting a Maya mesh with a simple Maya shading setup results in the correct shading on the USD mesh. """ # Validate the displayColor on the mesh prim. cubePrim = self._stage.GetPrimAtPath('/RedCube/Geom/Cube') self.assertTrue(cubePrim) cubeMesh = UsdGeom.Mesh(cubePrim) self.assertTrue(cubeMesh) meshDisplayColors = cubeMesh.GetDisplayColorPrimvar().Get() self.assertEqual(len(meshDisplayColors), 1) self.assertTrue(Gf.IsClose(meshDisplayColors[0], self.RED_COLOR, 1e-6)) # Validate the Material prim bound to the Mesh prim. material = UsdShade.Material.GetBoundMaterial(cubePrim) self.assertTrue(material) materialPath = material.GetPath().pathString self.assertEqual(materialPath, '/RedCube/Looks/RedLambertSG') materialInputs = material.GetInputs() self.assertEqual(len(materialInputs), 3) materialInput = material.GetInput('displayColor') matDisplayColor = materialInput.Get() self.assertTrue(Gf.IsClose(matDisplayColor, self.RED_COLOR, 1e-6)) # Just verify that displayOpacity and transparency exist. materialInput = material.GetInput('displayOpacity') self.assertTrue(materialInput) materialInput = material.GetInput('transparency') self.assertTrue(materialInput) # Validate the surface shader that is connected to the material. # XXX: Note that the expected number of outputs here is two rather than # one, since we are still authoring the UsdRi Bxdf source in addition # to the surface terminal for backwards compatibility. When consumers # are updated to use the surface terminal instead, this test will have # to be updated. materialOutputs = material.GetOutputs() self.assertEqual(len(materialOutputs), 2) materialOutput = material.GetOutput('surface') (connectableAPI, outputName, outputType) = materialOutput.GetConnectedSource() self.assertEqual(outputName, 'out') shader = UsdShade.Shader(connectableAPI) self.assertTrue(shader) self.assertEqual(shader.GetPrim().GetName(), 'RedLambertSG_lambert') # XXX: Validate the UsdRi Bxdf. This must also be removed when we no # longer author it. from pxr import UsdRi usdRiMaterialAPI = UsdRi.MaterialAPI(material.GetPrim()) self.assertTrue(usdRiMaterialAPI) bxdf = usdRiMaterialAPI.GetBxdf() self.assertEqual(bxdf.GetPrim(), shader.GetPrim()) shaderId = shader.GetIdAttr().Get() self.assertEqual(shaderId, 'PxrDiffuse') shaderInputs = shader.GetInputs() self.assertEqual(len(shaderInputs), 2) diffuseInput = shader.GetInput('diffuseColor') self.assertTrue(diffuseInput) (connectableAPI, outputName, outputType) = diffuseInput.GetConnectedSource() self.assertEqual(outputName, 'displayColor') self.assertTrue(connectableAPI) self.assertEqual(connectableAPI.GetPath().pathString, materialPath) transmissionInput = shader.GetInput('transmissionColor') self.assertTrue(transmissionInput) (connectableAPI, outputName, outputType) = transmissionInput.GetConnectedSource() self.assertEqual(outputName, 'transparency') self.assertTrue(connectableAPI) self.assertEqual(connectableAPI.GetPath().pathString, materialPath)