- Substance 3D home
- Home
- Command Line Tools
- Command Line overview
- sbsbaker
- sbscooker
- sbsmtools
- sbsmutator
- sbsrender
- sbsupdater
- Command Line overview
- Pysbs - Python API
- Pysbs - Python API overview
- Getting started
- General topics
- Examples
- API Content
- API Content overview
- Substance definitions
- Common interfaces
- compnode
- context projectmgr
- graph
- mdl
- modelgraphindex
- modelannotationnames
- modelgraph
- modelgraphgenerator
- modelgraphimplementation
- modelnodenames
- modeloperand
- modulegraphindex
- moduleannotation
- moduleconnection
- modulegraph
- modulegraphgenerator
- modulegraphimplementation
- modulegraphlibrary
- modulegraphregister
- modulenode
- modulenodeimplementation
- modulenodeinstance
- moduleoperand
- moduleoutputbridging
- moduleparaminput
- params
- projectmgrdoc
- sbsarchive
- sbscommon
- sbspreset
- sbsproject
- substance
- Libraries
- sbsenum
- sbslibrary
- sbsbakerslibrary
- Helpers
- Execution context
- API Change log
- Samples
- Setup and Getting Started
- Integrations
- Substance Maya toolset
- Changelog overview
demos
Module demos provides samples of usage of Pysbs.
demos.demoBakingParameters(aContext, aFileAbsPath='', aDestFileAbsPath='')
Demonstrates the creation and edition of the baking parameters
Parameters: |
|
---|---|
Returns: | Nothing |
Here is the code of function demoBakingParameters:
if aFileAbsPath == '' or aDestFileAbsPath == '': log.error("Please provide the appropriate arguments: aFileAbsPath and aDestFileAbsPath") return False try: # Parse the .sbs file and provide the object structure of the entire substance sbsDoc = substance.SBSDocument(aContext, aFileAbsPath) if sbsDoc.parseDoc(): # Add a new Scene resource to the document aRelPath = sbsDoc.buildAbsPathFromRelToMePath(aRelPathFromPackage='./Models/m41_low.fbx') aNewResource = sbsDoc.createLinkedResource(aIdentifier='LowResMesh', aResourcePath=aRelPath, aResourceTypeEnum=sbsenum.ResourceTypeEnum.SCENE) # Create BakingParameters for this resource aBakingParams = aNewResource.createBakingParameters() # Add a high poly mesh from a file path aHighPolyFilePath = sbsDoc.buildAbsPathFromRelToMePath('./Models/m41_high.fbx') aBakingParams.addHighDefinitionMeshFromFile(aHighPolyFilePath) # Set default Antialiasing value aBakingParams.setParameterValue(sbsbakers.ConverterParamEnum.DEFAULT__SUB_SAMPLING, sbsbakers.BakerFromMeshSubSamplingEnum.SUBSAMPLING_4x4) # Add a Bent Normal From Mesh baker BN_baker = aBakingParams.addBaker(sbsbakers.BakerEnum.BENT_NORMALS_FROM_MESH) # Add a Normal Map From Mesh baker NM_baker = aBakingParams.addBaker(sbsbakers.BakerEnum.NORMAL_MAP_FROM_MESH) # Set Antialiasing value specifically to NormalMap baker NM_baker.setParameterValue(aParameter=sbsbakers.ConverterParamEnum.DETAIL__SUB_SAMPLING, aParamValue=sbsbakers.BakerFromMeshSubSamplingEnum.SUBSAMPLING_2x2) # Add an Ambient Occlusion baker which uses the resulting map of the Normal Map From Mesh baker AO_baker = aBakingParams.addBaker(sbsbakers.BakerEnum.AMBIENT_OCCLUSION) AO_baker.setFileParameterValueFromPreviousBaker(aParameter=sbsbakers.ConverterParamEnum.ADDITIONAL__NORMAL_MAP, aPreviousBaker=NM_baker) # Set back the baking parameters into the options of the second resource aNewResource.setBakingParameters(aBakingParams) # Write back the document structure into the destination .sbs file sbsDoc.writeDoc(aNewFileAbsPath = aDestFileAbsPath) log.info("=> Resulting substance saved at %s" % aDestFileAbsPath) return True except BaseException as error: log.error("!!! [demoBakingParameters] Failed to edit the baking parameters") raise error
demos.demoBuildSBSFromPainterBitmaps(aContext, aDestFileAbsPath='')
Create a graph with as many Bitmap & Output node as picture files in the Painter folder
Parameters: |
|
---|---|
Returns: | Nothing |
Here is the code of function demoBuildSBSFromPainterBitmaps:
if aDestFileAbsPath == '': log.error("Please provide the appropriate arguments: aDestFileAbsPath") return False xOffset = [150, 0, 0] yOffset = [0, 150, 0] initPos = [0,0, 0] try: # Create a new SBSDocument from scratch sbsDoc = sbsgenerator.createSBSDocument(aContext, aFileAbsPath = aDestFileAbsPath, aGraphIdentifier = 'PainterFilter', aParameters = {sbsenum.CompNodeParamEnum.OUTPUT_SIZE:[sbsenum.OutputSizeEnum.SIZE_1024,sbsenum.OutputSizeEnum.SIZE_1024], sbsenum.CompNodeParamEnum.OUTPUT_FORMAT:sbsenum.OutputFormatEnum.FORMAT_16BITS}, aInheritance = {sbsenum.CompNodeParamEnum.OUTPUT_SIZE:sbsenum.ParamInheritanceEnum.ABSOLUTE, sbsenum.CompNodeParamEnum.OUTPUT_FORMAT:sbsenum.ParamInheritanceEnum.ABSOLUTE}) aGraph = sbsDoc.getSBSGraph(aGraphIdentifier = 'PainterFilter') # Retrieve bitmaps aPathOutputs = sbsDoc.mDirAbsPath + os.path.sep aListOutputs = glob.glob(aPathOutputs+"*.png") log.info(len(aListOutputs)) for x in range(0,len(aListOutputs)): log.info(aListOutputs[x]) # Create a Bitmap node aBitmapNode = aGraph.createBitmapNode(aSBSDocument = sbsDoc, aResourcePath = aListOutputs[x], aGUIPos = [y * x for y in yOffset], aParameters = {sbsenum.CompNodeParamEnum.COLOR_MODE:True}, aCookedFormat = sbsenum.BitmapFormatEnum.JPG, aCookedQuality = 1) aId = aListOutputs[x][aListOutputs[x].rfind(os.path.sep)+1:-4] # Create a Output color node aOutputNode = aGraph.createOutputNode(aIdentifier = aId, aGUIPos = map(sum, zip([y * x for y in yOffset], xOffset)), aOutputFormat = sbsenum.TextureFormatEnum.DEFAULT_FORMAT, aAttributes = {sbsenum.AttributesEnum.Description: 'Exported from painter: %s' % aId}, aMipmaps = sbsenum.MipmapEnum.LEVELS_12, aUsages = {sbsenum.UsageEnum.DIFFUSE: {sbsenum.UsageDataEnum.COMPONENTS:sbsenum.ComponentsEnum.RGBA}, sbsenum.UsageEnum.HEIGHT: {sbsenum.UsageDataEnum.COMPONENTS:sbsenum.ComponentsEnum.R}}) aGraph.connectNodes(aLeftNode = aBitmapNode, aRightNode = aOutputNode, aRightNodeInput = sbsenum.InputEnum.INPUT_NODE_OUTPUT ) # Update node position initPos += yOffset # Write back the document structure into the destination .sbs file sbsDoc.writeDoc() log.info("=> Resulting substance saved at %s" % aDestFileAbsPath) return True except BaseException as error: log.error("!!! [demoBuildSBSFromPainterBitmaps] Failed to create the new package") raise error
demos.demoCreation(aContext, aDestFileAbsPath='')
- Demonstrates all what is possible to create using this API:
-
- A new substance from scratch
- Compositing graph (all filters, instance of graphs, inputs and outputs…)
- Function graph (all functions, instance of functions, …)
- Definition of input parameters for graphs and functions
- Definition of a dynamic parameter
Parameters: |
|
---|---|
Returns: | Nothing |
Here is the code of function demoCreation:
if aDestFileAbsPath == '': log.error("Please provide the appropriate arguments: aFileAbsPath and aDestFileAbsPath") return False try: # Create a new package sbsDoc = sbsgenerator.createSBSDocument(aContext, aDestFileAbsPath) aGraph = sbsDoc.createGraph(aGraphIdentifier = 'MyGraph', aParameters = {sbsenum.CompNodeParamEnum.OUTPUT_FORMAT:sbsenum.OutputFormatEnum.FORMAT_16BITS}, aInheritance= {sbsenum.CompNodeParamEnum.OUTPUT_FORMAT:sbsenum.ParamInheritanceEnum.ABSOLUTE}) aSubGraph = sbsDoc.createGraph(aGraphIdentifier = 'MySubGraph') aFunction = sbsDoc.createFunction(aFunctionIdentifier = 'MyFunction') aResourceGroup = sbsDoc.createGroup( aParentFolder = 'MyResources', aGroupIdentifier = 'Bitmaps' ) startPos = [48, 48, 0] xOffset = [192, 0, 0] yOffset = [0, 192, 0] xyOffset = [192, 96, 0] # ------------------------------------------------------------------------------------------ # Create the graph 'MySubGraph' # ------------------------------------------------------------------------------------------ # Create Input parameters for MySubGraph # - Parameter InputColor(RGBA) aSubGraph.addInputParameter(aIdentifier = 'InputColor', aWidget = sbsenum.WidgetEnum.COLOR_FLOAT4, aDefaultValue = [1,1,1,1], aLabel = 'Input Color') # - Parameter Blending(DropDown list) aParam = aSubGraph.addInputParameter(aIdentifier = 'Blending', aWidget = sbsenum.WidgetEnum.DROPDOWN_INT1, aLabel = 'Blending') aParam.setDropDownList(aValueMap={sbsenum.BlendBlendingModeEnum.MULTIPLY: 'Multiply', sbsenum.BlendBlendingModeEnum.OVERLAY: 'Overlay', sbsenum.BlendBlendingModeEnum.SOFT_LIGHT: 'Soft Light'}) aParam.setDefaultValue(sbsenum.BlendBlendingModeEnum.MULTIPLY) # Create the content of the graph MySubGraph # - Uniform color filter aUniformColor = aSubGraph.createCompFilterNode(aFilter = sbsenum.FilterEnum.UNIFORM, aParameters = {sbsenum.CompNodeParamEnum.COLOR_MODE: sbsenum.ColorModeEnum.COLOR, sbsenum.CompNodeParamEnum.OUTPUT_COLOR: [0.54,0.063,0,1]}, aGUIPos=startPos) # - Input node color aInputNode = aSubGraph.createInputNode(aIdentifier = 'MyInput', aColorMode = sbsenum.ColorModeEnum.COLOR, aGUIPos = aUniformColor.getOffsetPosition(yOffset), aAttributes = {sbsenum.AttributesEnum.Label: 'My Input'}, aUsages = {sbsenum.UsageEnum.BASECOLOR:{sbsenum.UsageDataEnum.COMPONENTS:sbsenum.ComponentsEnum.RGB}}) # - Blend filter aBlendNode = aSubGraph.createCompFilterNode(aFilter = sbsenum.FilterEnum.BLEND, aGUIPos = aUniformColor.getOffsetPosition(xyOffset), aParameters = {sbsenum.CompNodeParamEnum.BLENDING_MODE: sbsenum.BlendBlendingModeEnum.MULTIPLY, sbsenum.CompNodeParamEnum.OPACITY: 0.67}, aInheritance = {sbsenum.CompNodeParamEnum.OUTPUT_SIZE: sbsenum.ParamInheritanceEnum.PARENT}) # - Output node aOutputNode = aSubGraph.createOutputNode(aIdentifier = 'MyOutput', aGUIPos = aBlendNode.getOffsetPosition(xOffset), aOutputFormat = sbsenum.TextureFormatEnum.DEFAULT_FORMAT, aAttributes = {sbsenum.AttributesEnum.Description: 'SubGraph Output'}, aUsages = {sbsenum.UsageEnum.BASECOLOR: {sbsenum.UsageDataEnum.COMPONENTS:sbsenum.ComponentsEnum.RGBA}}) # Connect the nodes aSubGraph.connectNodes(aLeftNode = aInputNode, aRightNode = aBlendNode, aRightNodeInput = sbsenum.InputEnum.DESTINATION) aSubGraph.connectNodes(aLeftNode = aUniformColor, aRightNode = aBlendNode, aRightNodeInput = sbsenum.InputEnum.SOURCE) aSubGraph.connectNodes(aLeftNode = aBlendNode, aRightNode = aOutputNode, aRightNodeInput = sbsenum.InputEnum.INPUT_NODE_OUTPUT) # Define some dynamic parameters, handled by the input parameters defined in SubGraph: aDynFunction = aUniformColor.setDynamicParameter(sbsenum.CompNodeParamEnum.OUTPUT_COLOR) aDynFunction.setToInputParam(aParentGraph = aSubGraph, aInputParamIdentifier = 'InputColor') aDynFunction = aBlendNode.setDynamicParameter(sbsenum.CompNodeParamEnum.BLENDING_MODE) aDynFunction.setToInputParam(aParentGraph = aSubGraph, aInputParamIdentifier = 'Blending') # ------------------------------------------------------------------------------------------ # Create the function 'MyFunction' # ------------------------------------------------------------------------------------------ aFunction.initFunction() # - Definition of the function input parameter: BlurIntensity aParamBlur = 'BlurIntensity' aFunction.addInputParameter(aIdentifier = aParamBlur, aWidget = sbsenum.WidgetEnum.SLIDER_FLOAT1) # - Function node Get_Float(BlurIntensity) aNodeGet = aFunction.createFunctionNode(aFunction = sbsenum.FunctionEnum.GET_FLOAT1, aParameters = {sbsenum.FunctionEnum.GET_FLOAT1: aParamBlur}, aGUIPos=startPos) # - Function node Pi (instance included in package sbs://functions.sbs) aNodePi = aFunction.createFunctionInstanceNodeFromPath(aSBSDocument = sbsDoc, aPath = 'sbs://functions.sbs/Functions/Math/Pi', aGUIPos = aNodeGet.getOffsetPosition(yOffset)) # - Function node Mul aNodeMult = aFunction.createFunctionNode(aFunction = sbsenum.FunctionEnum.MUL, aGUIPos = aNodeGet.getOffsetPosition(xyOffset)) # Connect the nodes aFunction.connectNodes(aLeftNode = aNodeGet, aRightNode= aNodeMult, aRightNodeInput = sbsenum.FunctionInputEnum.A) aFunction.connectNodes(aLeftNode = aNodePi, aRightNode = aNodeMult, aRightNodeInput = sbsenum.FunctionInputEnum.B) aFunction.setOutputNode(aNodeMult) # ------------------------------------------------------------------------------------------ # Create the graph 'MyGraph' # ------------------------------------------------------------------------------------------ # Create Input parameters for MyGraph aParam = aGraph.addInputParameter(aIdentifier = aParamBlur, aWidget = sbsenum.WidgetEnum.SLIDER_FLOAT1, aLabel = 'Blur Intensity') aParam.setDefaultValue(0.5) aParam.setMaxValue(3) # Create the content of MyGraph # - FxMap Node aFxMapNode = aGraph.createCompFilterNode(aFilter=sbsenum.FilterEnum.FXMAPS, aParameters={sbsenum.CompNodeParamEnum.COLOR_MODE: sbsenum.ColorModeEnum.GRAYSCALE, sbsenum.CompNodeParamEnum.RANDOM_SEED: 5}, aGUIPos=startPos) # - Creation of the FxMap graph: aFxMapGraph = aFxMapNode.getFxMapGraph() # - First Quadrant node (root) aQuadrant1 = aFxMapGraph.createFxMapNode(aFxMapNode = sbsenum.FxMapNodeEnum.QUADRANT) aFxMapGraph.setRootNode(aQuadrant1) # - Second Quadrant node aQuadrant2 = aFxMapGraph.createFxMapNode(aFxMapNode = sbsenum.FxMapNodeEnum.QUADRANT, aGUIPos = aQuadrant1.getOffsetPosition(yOffset)) # - Third Quadrant node aQuadrant3 = aFxMapGraph.createFxMapNode(aFxMapNode = sbsenum.FxMapNodeEnum.QUADRANT, aGUIPos = aQuadrant2.getOffsetPosition(yOffset), aParameters = {sbsenum.CompNodeParamEnum.FX_PATTERN_TYPE: sbsenum.FX_PatternType.PYRAMID}) # - Define several functions for the third quadrant node # => Random luminosity (Float1 between 0 and 1) aFuncLum = aQuadrant3.setDynamicParameter(sbsenum.CompNodeParamEnum.FX_COLOR_LUM) aFloatNode = aFuncLum.createFunctionNode(aFunction = sbsenum.FunctionEnum.CONST_FLOAT, aParameters = {sbsenum.FunctionEnum.CONST_FLOAT: 1}) aRandNode = aFuncLum.createFunctionNode(aFunction = sbsenum.FunctionEnum.RAND, aGUIPos = aFloatNode.getOffsetPosition(xOffset)) aFuncLum.connectNodes(aLeftNode=aFloatNode, aRightNode=aRandNode) aFuncLum.setOutputNode(aRandNode) # => Random pattern rotation (Float1 between 0 and 1) aFuncRotation = aFuncLum.copy() aQuadrant3.setParameterValue(sbsenum.CompNodeParamEnum.FX_PATTERN_ROTATION, aFuncRotation) # => Random pattern offset (Float2 between -1 and 1) aFuncOffset = aQuadrant3.setDynamicParameter(sbsenum.CompNodeParamEnum.FX_PATTERN_OFFSET) aRandNode = aFuncOffset.createFunctionInstanceNodeFromPath(aSBSDocument=sbsDoc, aPath = 'sbs://functions.sbs/Functions/Random/Uniform_[-1,1[') aRandNode2 = aFuncOffset.createFunctionInstanceNodeFromPath(aSBSDocument=sbsDoc, aPath = 'sbs://functions.sbs/Functions/Random/Uniform_[-1,1[', aGUIPos = aRandNode.getOffsetPosition(yOffset)) aVec2Node = aFuncOffset.createFunctionNode(aFunction = sbsenum.FunctionEnum.VECTOR2, aGUIPos = aRandNode.getOffsetPosition(xyOffset)) aFuncOffset.connectNodes(aLeftNode = aRandNode, aRightNode = aVec2Node, aRightNodeInput = sbsenum.FunctionInputEnum.COMPONENTS_IN) aFuncOffset.connectNodes(aLeftNode = aRandNode2, aRightNode = aVec2Node, aRightNodeInput = sbsenum.FunctionInputEnum.COMPONENTS_LAST) aFuncOffset.setOutputNode(aVec2Node) # => Random pattern size (Float2 between 0.5 and 2) aFuncSize = aQuadrant3.setDynamicParameter(sbsenum.CompNodeParamEnum.FX_PATTERN_SIZE) aFloatNode1 = aFuncSize.createFunctionNode(aFunction = sbsenum.FunctionEnum.CONST_FLOAT, aParameters = {sbsenum.FunctionEnum.CONST_FLOAT: 0.5}) aFloatNode2 = aFuncSize.createFunctionNode(aFunction = sbsenum.FunctionEnum.CONST_FLOAT, aParameters = {sbsenum.FunctionEnum.CONST_FLOAT: 2}, aGUIPos = aFloatNode1.getOffsetPosition(yOffset)) aRandNode = aFuncSize.createFunctionInstanceNodeFromPath(aSBSDocument=sbsDoc, aPath = 'sbs://functions.sbs/Functions/Random/Uniform_[A,B[', aGUIPos = aFloatNode1.getOffsetPosition(xyOffset)) aVec2Node = aFuncSize.createFunctionNode(aFunction = sbsenum.FunctionEnum.VECTOR2, aGUIPos = aRandNode.getOffsetPosition(xOffset)) aFuncSize.connectNodes(aLeftNode = aFloatNode1, aRightNode = aRandNode, aRightNodeInput = 'A') aFuncSize.connectNodes(aLeftNode = aFloatNode2, aRightNode = aRandNode, aRightNodeInput = 'B') aFuncSize.connectNodes(aLeftNode = aRandNode, aRightNode = aVec2Node, aRightNodeInput = sbsenum.FunctionInputEnum.COMPONENTS_IN) aFuncSize.connectNodes(aLeftNode = aRandNode, aRightNode = aVec2Node, aRightNodeInput = sbsenum.FunctionInputEnum.COMPONENTS_LAST) aFuncSize.setOutputNode(aVec2Node) # - Fourth and Fifth Quadrant nodes, copies of the third one aQuadrant4 = aFxMapGraph.duplicateNode(aQuadrant3, aGUIOffset = yOffset) aQuadrant5 = aFxMapGraph.duplicateNode(aQuadrant4, aGUIOffset = yOffset) # - Connections of the quadrant nodes aFxMapGraph.connectNodes(aTopNode = aQuadrant1, aBottomNode = aQuadrant2) aFxMapGraph.connectNodes(aTopNode = aQuadrant2, aBottomNode = aQuadrant3) aFxMapGraph.connectNodes(aTopNode = aQuadrant3, aBottomNode = aQuadrant4) aFxMapGraph.connectNodes(aTopNode = aQuadrant4, aBottomNode = aQuadrant5) # - Gradient Filter with key values gradientKeyValues = [sbslibrary.GradientKey(aPosition = 0, aValue = [0,0,0,1]), sbslibrary.GradientKey(aPosition = 0.330, aValue = [1,1,1,1])] aGradientNode = aGraph.createGradientMapNode(aGUIPos = aFxMapNode.getOffsetPosition(xOffset), aKeyValues = gradientKeyValues, aParameters= {sbsenum.CompNodeParamEnum.GRADIENT_ADDRESSING: sbsenum.GradientAddressingEnum.REPEAT}) # - Instance of graph SubGraph created previously aInstanceNode = aGraph.createCompInstanceNode(aSBSDocument = sbsDoc, aGraph = aSubGraph, aGUIPos = aGradientNode.getOffsetPosition(xOffset)) # - Instance of substance Blur_Hq included in the default package sbs:// aBlurHQNode = aGraph.createCompInstanceNodeFromPath(aSBSDocument= sbsDoc, aPath = 'sbs://blur_hq.sbs/blur_hq', aGUIPos = aInstanceNode.getOffsetPosition(xOffset), aParameters = {'Intensity':2.8}) # - Definition of a dynamic parameter for the Blur_Hq Intensity parameter: aBlurFunction = aBlurHQNode.setDynamicParameter(aParameter = 'Intensity') aGetFloatNode = aBlurFunction.createFunctionNode(aFunction = sbsenum.FunctionEnum.GET_FLOAT1, aParameters = {sbsenum.FunctionEnum.GET_FLOAT1: aParamBlur}) # - Creation of an instance of function MyFunction defined previously: aFctInstanceNode = aBlurFunction.createFunctionInstanceNode(aSBSDocument = sbsDoc, aFunction = aFunction, aGUIPos = aGetFloatNode.getOffsetPosition(xOffset)) # - Connect the nodes aBlurFunction.connectNodes(aLeftNode = aGetFloatNode, aRightNode = aFctInstanceNode) aBlurFunction.setOutputNode(aFctInstanceNode) # - SVG node aSvgPath = sbsDoc.buildAbsPathFromRelToMePath('Bitmaps/SD_Icon_Color.svg' ) aSVGNode = aGraph.createSvgNode(aSBSDocument = sbsDoc, aResourcePath = aSvgPath, aResourceGroup = aResourceGroup, aGUIPos = aBlurHQNode.getOffsetPosition(xOffset), aParameters = {sbsenum.CompNodeParamEnum.COLOR_MODE:sbsenum.ColorModeEnum.COLOR, sbsenum.CompNodeParamEnum.OUTPUT_SIZE:[sbsenum.OutputSizeEnum.SIZE_1024,sbsenum.OutputSizeEnum.SIZE_1024], sbsenum.CompNodeParamEnum.TILING_MODE:sbsenum.TilingEnum.NO_TILING}, aInheritance = {sbsenum.CompNodeParamEnum.OUTPUT_SIZE:sbsenum.ParamInheritanceEnum.ABSOLUTE, sbsenum.CompNodeParamEnum.TILING_MODE:sbsenum.ParamInheritanceEnum.INPUT}, aCookedQuality = 0.5) # - Output node aOutputNode = aGraph.createOutputNode(aIdentifier = 'MainOutput', aGUIPos = aSVGNode.getOffsetPosition(xOffset), aOutputFormat = sbsenum.TextureFormatEnum.DEFAULT_FORMAT, aAttributes = {sbsenum.AttributesEnum.Description: 'Main Output'}, aMipmaps = sbsenum.MipmapEnum.LEVELS_12, aUsages = {sbsenum.UsageEnum.BASECOLOR: {sbsenum.UsageDataEnum.COMPONENTS:sbsenum.ComponentsEnum.RGBA}}) # Connect the nodes aGraph.connectNodes(aLeftNode = aFxMapNode, aRightNode = aGradientNode) aGraph.connectNodes(aLeftNode = aGradientNode, aRightNode = aInstanceNode, aRightNodeInput = 'MyInput') aGraph.connectNodes(aLeftNode = aInstanceNode, aRightNode = aBlurHQNode) aGraph.connectNodes(aLeftNode = aBlurHQNode, aRightNode = aSVGNode) aGraph.connectNodes(aLeftNode = aSVGNode, aRightNode = aOutputNode) # Tweak parameters aInstanceNode.getParameterValue('InputColor') aInstanceNode.setParameterValue('InputColor', [1, 0, 0, 1]) aInstanceNode.setParameterValue('Blending', sbsenum.BlendBlendingModeEnum.OVERLAY) # Set graph attributes and icon aGraph.setAttribute(aAttributeIdentifier = sbsenum.AttributesEnum.Author, aAttributeValue = 'Substance Designer API') aGraph.setIcon(aIconAbsPath = sbsDoc.buildAbsPathFromRelToMePath('Bitmaps/graphIcon.jpg')) # Write the document structure into the destination .sbs file sbsDoc.writeDoc() log.info("=> Resulting substance saved at %s" % aDestFileAbsPath) return True except BaseException as error: log.error("!!! [demoCreation] Failed to create the new package") raise error
demos.demoCreationMDL(aContext, aDestFileAbsPath='')
- Demonstrates the MDL graph creation using this API:
-
- MDL Graph
- MDL Nodes of any kind (constants, native mdl nodes, mdl graph instances, …)
- Declaring the input of the graph
- Setting parameters and annotations
- Create resources dedicated to MDL graphs (light profile or bsdf measurement)
Parameters: |
|
---|---|
Returns: | Nothing |
Here is the code of function demoCreationMDL:
if aDestFileAbsPath == '': log.error("Please provide the appropriate arguments: aFileAbsPath and aDestFileAbsPath") return False try: startPos = [48, 48, 0] xOffset = [192, 0, 0] yOffset = [0, 192, 0] xyOffset = [192, 96, 0] # Create a new package and a MDL graph sbsDoc = sbsgenerator.createSBSDocument(aContext, aDestFileAbsPath) mdlGraph = sbsDoc.createMDLGraph(aGraphIdentifier='DemoMDLGraph', aCreateOutputNode=True) # Create a new Substance graph, which will be used in the MDL graph sbsGraph = sbsDoc.createGraph(aGraphIdentifier='SBSGraph') aNode = sbsGraph.createCompFilterNode(aFilter=sbsenum.FilterEnum.UNIFORM, aParameters={sbsenum.CompNodeParamEnum.OUTPUT_COLOR:[0,0,1,1]}, aGUIPos=startPos) aOutput = sbsGraph.createOutputNode(aIdentifier='Output', aGUIPos=aNode.getOffsetPosition(xOffset)) sbsGraph.connectNodes(aLeftNode=aNode, aRightNode=aOutput) # Create the microfacet ggx branch inputRoughness = mdlGraph.createMDLNodeConst(aName='roughness', aConstTypePath='mdl::float', aExposed=True, aValue=0.5, aAnnotations={mdl.mdlenum.MDLAnnotationEnum.DISPLAY_NAME:'Roughness', mdl.mdlenum.MDLAnnotationEnum.GAMMA_TYPE:1, mdl.mdlenum.MDLAnnotationEnum.SAMPLER_USAGE:'roughness', mdl.mdlenum.MDLAnnotationEnum.HARD_RANGE:[0,1]}, aGUIPos=startPos) sbsInstance = mdlGraph.createMDLNodeSBSGraphInstance(aSBSDocument=sbsDoc, aGraph=sbsGraph, aGUIPos=inputRoughness.getOffsetPosition(yOffset)) mulNode = mdlGraph.createMDLNodeInstance(aPath='mdl::operator*(float,float)', aGUIPos=inputRoughness.getOffsetPosition(xOffset)) ggxNode = mdlGraph.createMDLNodeInstance(aPath='mdl::df::microfacet_ggx_smith_bsdf$1.5(float,float,color,float3,::df::scatter_mode,string)', aGUIPos=mulNode.getOffsetPosition(xyOffset)) mdlGraph.connectNodes(aLeftNode=inputRoughness, aRightNode=mulNode, aRightNodeInput='x') mdlGraph.connectNodes(aLeftNode=inputRoughness, aRightNode=mulNode, aRightNodeInput='y') mdlGraph.connectNodes(aLeftNode=mulNode, aRightNode=ggxNode, aRightNodeInput='roughness_u') mdlGraph.connectNodes(aLeftNode=mulNode, aRightNode=ggxNode, aRightNodeInput='roughness_v') mdlGraph.connectNodes(aLeftNode=sbsInstance, aRightNode=ggxNode, aRightNodeInput='tint') # Create a new light profile resource aPath = sbsDoc.buildAbsPathFromRelToMePath('Bitmaps/Comet.IES') aRes = sbsDoc.createLinkedResource(aResourcePath=aPath,aResourceTypeEnum=sbsenum.ResourceTypeEnum.LIGHT_PROFILE) # Create a IES profile node that uses this resource and generate a 'material_emission' iesNode = mdlGraph.createMDLNodeInstance(aPath='mdl::light_profile(string)', aGUIPos=sbsInstance.getOffsetPosition(yOffset)) iesNode.setParameterValue(aParameter='name', aParamValue=aRes.getPkgResourcePath()) edfNode = mdlGraph.createMDLNodeInstance(aPath='mdl::df::measured_edf(light_profile,float,bool,float3x3,float3,string)', aParameters={'multiplier':0.01}, aGUIPos=iesNode.getOffsetPosition(xOffset)) matEmissionNode = mdlGraph.createMDLNodeInstance(aPath='mdl::material_emission(edf,color,intensity_mode)', aParameters={'intensity':[0.000619,0.000387,0.000077]}, aGUIPos=edfNode.getOffsetPosition(xOffset)) mdlGraph.connectNodes(aLeftNode=iesNode, aRightNode=edfNode) mdlGraph.connectNodes(aLeftNode=edfNode, aRightNode=matEmissionNode) # Handle the material_geometry stateNormal = mdlGraph.createMDLNodeInstance(aPath='mdl::state::normal()', aGUIPos=iesNode.getOffsetPosition(yOffset)) inputNormal = mdlGraph.createMDLNodeConst(aName='normal', aConstTypePath='mdl::float3', aExposed=True, aAnnotations={mdl.mdlenum.MDLAnnotationEnum.DISPLAY_NAME:'Normal', mdl.mdlenum.MDLAnnotationEnum.GAMMA_TYPE:1, mdl.mdlenum.MDLAnnotationEnum.SAMPLER_USAGE:'normal'}, aGUIPos=stateNormal.getOffsetPosition(xOffset)) matGeometryNode = mdlGraph.createMDLNodeInstance(aPath='mdl::material_geometry(float3,float,float3)', aGUIPos=inputNormal.getOffsetPosition(xOffset)) mdlGraph.connectNodes(aLeftNode=stateNormal, aRightNode=inputNormal) mdlGraph.connectNodes(aLeftNode=inputNormal, aRightNode=matGeometryNode, aRightNodeInput='normal') # Create the material_surface matSurfaceNode = mdlGraph.createMDLNodeInstance(aPath='mdl::material_surface(bsdf,material_emission)', aGUIPos=ggxNode.getOffsetPosition(xyOffset)) matSurfaceNode.setPinVisibilityForParameter(aParameter='emission', aVisible=True) mdlGraph.connectNodes(aLeftNode=ggxNode, aRightNode=matSurfaceNode) mdlGraph.connectNodes(aLeftNode=matEmissionNode, aRightNode=matSurfaceNode) # Get the output node outputNode = mdlGraph.getGraphOutput() outputNode.setPosition(matSurfaceNode.getOffsetPosition(xyOffset)) mdlGraph.connectNodes(aLeftNode=matSurfaceNode, aRightNode=outputNode) mdlGraph.connectNodes(aLeftNode=matGeometryNode, aRightNode=outputNode) # Write back the document structure into the destination .sbs file sbsDoc.writeDoc(aNewFileAbsPath=aDestFileAbsPath) del sbsDoc log.info("=> Resulting substance saved at %s" % aDestFileAbsPath) return True except BaseException as error: log.error("!!! [demoCreationMDL] Failed to modify package") raise error
demos.demoExportWithDependencies(aContext, aFileAbsPath='', aDestFolderAbsPath='')
Export the given package into the given destination folder
Parameters: |
|
---|---|
Returns: | Nothing |
Here is the code of function demoExportWithDependencies:
if aFileAbsPath == '' or aDestFolderAbsPath == '': log.error("Please provide the appropriate arguments: aFileAbsPath and aDestFolderAbsPath") return False try: python_helpers.createFolderIfNotExists(aDestFolderAbsPath) # Parse the document to export sbsDoc = substance.SBSDocument(aContext, aFileAbsPath) sbsDoc.parseDoc() # Create an exporter aExporter = sbsexporter.SBSExporter() # Export the package into an archived self-contained package, in the folder aDestFolderAbsPath # The resources and dependencies of this package will be included in the archive, including the ones referred by the alias sbs:// aResultingArchive = aExporter.export(aSBSDocument = sbsDoc, aExportFolder = aDestFolderAbsPath, aBuildArchive = True, aAliasesToExport = ['sbs']) log.info("=> Archive created at %s" % aResultingArchive) # Same as before, without archiving the resulting folder aResultingPath = aExporter.export(aSBSDocument = sbsDoc, aExportFolder = aDestFolderAbsPath, aAliasesToExport = ['sbs']) log.info("=> Substance exported with its dependencies at %s" % aResultingPath) return True except BaseException as error: log.error("!!! [demoExportWithDependencies] Failed to export the package") raise error
demos.demoIteration(aContext, aFileAbsPath='', aDestFileAbsPath='')
Demonstrates the iteration creation of a single node and of a complete pattern.
Parameters: |
|
---|---|
Returns: | Nothing |
Here is the code of function demoIteration:
if aFileAbsPath == '' or aDestFileAbsPath == '': log.error("Please provide the appropriate arguments: aFileAbsPath and aDestFileAbsPath") return False try: # Parse the .sbs file and provide the object structure of the entire substance sbsDoc = substance.SBSDocument(aContext, aFileAbsPath) sbsDoc.parseDoc() # Duplicate 5 times a single node aGraph = sbsDoc.getSBSGraph(aGraphIdentifier = 'DemoIterationSubGraph') aGraph.createIterationOnNode(aNbIteration = 5, aNodeUID = '1255032103') # Duplicate 3 times the node (test the automatic detection of compatible inputs / outputs) aGraph = sbsDoc.getSBSGraph(aGraphIdentifier = 'DemoIterationSubGraphDouble') aGraph.createIterationOnNode(aNbIteration = 3, aNodeUID = '1255523774') # Duplicate 3 times the pattern of nodes (test the automatic detection of compatible inputs / outputs) aGraph = sbsDoc.getSBSGraph(aGraphIdentifier='DemoIterationPattern') aGraph.createIterationOnPattern(aNbIteration=3, aNodeUIDs=['1255034408', '1255026224', '1255029181', '1255029884', '1255029987', '1255029994', '1255029049']) # Duplicate 3 times the pattern of nodes, specifying way to connect two successive patterns aGraph = sbsDoc.getSBSGraph(aGraphIdentifier = 'DemoIterationVerticalPattern') aGraph.createIterationOnPattern(aNbIteration = 3, aNodeUIDs = ['1262168894', '1262168896'], aNodeUIDs_NextPattern = ['1262169024', '1262168960'], aGUIOffset = [0, 120]) # Write back the document structure into the destination .sbs file sbsDoc.writeDoc(aNewFileAbsPath = aDestFileAbsPath) del sbsDoc log.info("=> Resulting substance saved at %s" % aDestFileAbsPath) return True except BaseException as error: log.error("!!! [demoIteration] Failed to modify package") raise error
demos.demoIterationFlame(aContext, aFileAbsPath='', aDestFileAbsPath='')
Demonstrates the iteration creation of a pattern inside a Function
Parameters: |
|
---|---|
Returns: | Nothing |
Here is the code of function demoIterationFlame:
if aFileAbsPath == '' or aDestFileAbsPath == '': log.error("Please provide the appropriate arguments: aFileAbsPath and aDestFileAbsPath") return False try: # Parse the .sbs file and provide the object structure of the entire substance sbsDoc = substance.SBSDocument(aContext, aFileAbsPath) sbsDoc.parseDoc() # Duplicate 63 times the pattern inside function RayMarch aFunction = sbsDoc.getSBSFunction(aFunctionIdentifier= 'RayMarch') createdNodes = aFunction.createIterationOnPattern(aNbIteration = 63, aGUIOffset = [0, 200], aNodeUIDs = ['1262101431', '1262101516'], aNodeUIDs_NextPattern = ['1262101533', '1262101527']) # Connect the last created node with the end of the function aEndNode = aFunction.getNode('1262095290') aFunction.connectNodes(aLeftNode = createdNodes[-1], aRightNode = aEndNode, aRightNodeInput = sbsenum.FunctionInputEnum.SEQUENCE_IN) # Write back the document structure into the destination .sbs file sbsDoc.writeDoc(aNewFileAbsPath = aDestFileAbsPath) log.info("=> Resulting substance saved at %s" % aDestFileAbsPath) return True except BaseException as error: log.error("!!! [demoIterationFlame] Failed to create the iterations") raise error
demos.demoIterationPixProc(aContext, aFileAbsPath='', aDestFileAbsPath='')
Demonstrates the iteration inside a pixel processor.
Parameters: |
|
---|---|
Returns: | Nothing |
Here is the code of function demoIterationPixProc:
if aFileAbsPath == '' or aDestFileAbsPath == '': log.error("Please provide the appropriate arguments: aFileAbsPath and aDestFileAbsPath") pass try: # Parse the .sbs file and provide the object structure of the entire substance sbsDoc = substance.SBSDocument(aContext, aFileAbsPath) sbsDoc.parseDoc() # Get the graph 'TerrainMultiFractal' aGraph = sbsDoc.getSBSGraph(aGraphIdentifier = 'TerrainMultiFractal') # Get the pixel processor node where the iteration will be created, and its dynamic function aPixProcNode = aGraph.getNode('1260898088') aDynFct = aPixProcNode.getPixProcFunction() # Duplicate 10 times the pattern, indicating the way to reconnect to the next pattern createdNodes = aDynFct.createIterationOnPattern(aNbIteration = 10, aGUIOffset = [0, 200], aNodeUIDs = ['1263052178', '1263052114' ], aNodeUIDs_NextPattern = ['1263052279', '1263052278']) # Connect the last node of the iteration to the end part of the pixel processor function aDynFct.connectNodes(aLeftNode=createdNodes[-1], aRightNode='1257621570') aDynFct.connectNodes(aLeftNode=createdNodes[-1], aRightNode='1257624564') # Write back the document structure into the destination .sbs file sbsDoc.writeDoc(aNewFileAbsPath = aDestFileAbsPath) del sbsDoc log.info("=> Resulting substance saved at %s" % aDestFileAbsPath) return True except BaseException as error: log.error("!!! [demoIteration] Failed to modify package") raise error
demos.demoMassiveModification(aContext, aFileAbsPath='', aDestFileAbsPath='')
Demonstrates the massive modification of a Substance. In this sample, a substance containing 3 graph with lots of Input nodes will be modified so that all Graphs and Input nodes pixel format are set to 16 bits per channel, without inheritance from parent.
Parameters: |
|
---|---|
Returns: | Nothing |
Here is the code of function demoMassiveModification:
if aFileAbsPath == '' or aDestFileAbsPath == '': log.error("Please provide the appropriate arguments: aFileAbsPath and aDestFileAbsPath") return False try: # Parse the .sbs file and provide the object structure of the entire substance sbsDoc = substance.SBSDocument(aContext, aFileAbsPath) sbsDoc.parseDoc() # Parse all graphs for aGraph in sbsDoc.getSBSGraphList(): # Set pixel format and output size of the graph aGraph.setBaseParameterValue(aParameter = sbsenum.CompNodeParamEnum.OUTPUT_FORMAT, aParamValue = sbsenum.OutputFormatEnum.FORMAT_16BITS, aRelativeTo = sbsenum.ParamInheritanceEnum.ABSOLUTE) aGraph.setBaseParameterValue(aParameter = sbsenum.CompNodeParamEnum.OUTPUT_SIZE, aParamValue = [sbsenum.OutputSizeEnum.SIZE_1024,sbsenum.OutputSizeEnum.SIZE_1024], aRelativeTo = sbsenum.ParamInheritanceEnum.ABSOLUTE) # Set pixel format for all input nodes inputNodes = aGraph.getAllInputNodes() for inputNode in inputNodes: inputNode.setParameterValue(aParameter = sbsenum.CompNodeParamEnum.OUTPUT_FORMAT, aParamValue = sbsenum.OutputFormatEnum.FORMAT_16BITS, aRelativeTo = sbsenum.ParamInheritanceEnum.ABSOLUTE) # Write back the document structure into the destination .sbs file sbsDoc.writeDoc(aNewFileAbsPath = aDestFileAbsPath) del sbsDoc log.info("=> Resulting substance saved at %s" % aDestFileAbsPath) return True except BaseException as error: log.error("!!! [demoMassiveModification] Failed to modify package") raise error
demos.demoReadWriteSBS(aContext, aFileAbsPath='', aDestFileAbsPath='')
Allow to validate the deserialization and serialization of a .sbs without doing any modification on it.
Parameters: |
|
---|---|
Returns: | Nothing |
Here is the code of function demoReadWriteSBS:
if aFileAbsPath == '' or aDestFileAbsPath == '': log.error("Please provide the appropriate arguments: aFileAbsPath and aDestFileAbsPath") return False try: # Parse document sbsDoc = substance.SBSDocument(aContext, aFileAbsPath) sbsDoc.parseDoc() # Display its dependencies and resources log.info("Dependencies: ") for s in sbsDoc.getSBSDependencyList(): log.info(s.mFileAbsPath) log.info("nResources: ") for s in sbsDoc.getSBSResourceList(): log.info(s.getResolvedFilePath()) log.info(s.mFileAbsPath) # Write the document sbsDoc.writeDoc(aNewFileAbsPath = aDestFileAbsPath) log.info("n=> Resulting substance saved at %s" % aDestFileAbsPath) return True except BaseException as error: log.error("!!! [demoHelloWorld] Failed to create the new package") raise error