def generateOslShader(mtlx_file): doc = mx.createDocument() searchPath = os.path.join(_fileDir, "../libraries") _loadLibraries(doc, os.path.join(searchPath, "stdlib")) _loadLibraries(doc, os.path.join(searchPath, "pbrlib")) _loadLibraries(doc, os.path.join(searchPath, "appleseed")) mx.readFromXmlFileBase(doc, mtlx_file) # Find materials and shaderrefs inside mtlx file materials = doc.getMaterials() material = next(iter(materials)) if material is not None: shaderRefs = material.getShaderRefs() if shaderRefs is not None: shaderRef = next(iter(shaderRefs)) if shaderRef is None: return shadergen = genosl.OslShaderGenerator.create() context = genshader.GenContext(shadergen) # Add path to find all source code snippets context.registerSourceCodeSearchPath(mx.FilePath(searchPath)) # Add path to find OSL include files # context.registerSourceCodeSearchPath(mx.FilePath(os.path.join(searchPath, "stdlib/osl"))) print(mx.writeToXmlString(doc)) # Complete mode # context.getOptions().shaderInterfaceType = int(ShaderInterfaceType.SHADER_INTERFACE_COMPLETE) context.getOptions().shaderInterfaceType = int( genshader.ShaderInterfaceType.SHADER_INTERFACE_REDUCED) shaderRefName = shaderRef.getName() shader = shadergen.generate(shaderRefName, shaderRef, context) if shader is None: return if len(shader.getSourceCode(genshader.PIXEL_STAGE)) == 0: return osl_path = os.path.join(os.path.dirname(mtlx_file), shader.getName() + ".osl") with open(osl_path, "w+") as osl_file: osl_file.write(shader.getSourceCode(genshader.PIXEL_STAGE))
def test_ShaderInterface(self): doc = mx.createDocument() libraryFolders = ["stdlib"] filePath = os.path.dirname(os.path.abspath(__file__)) searchPath = os.path.join(filePath, "..", "..", "libraries") mx.loadLibraries(libraryFolders, searchPath, doc) exampleName = u"shader_interface" # Create a nodedef taking three color3 and producing another color3 nodeDef = doc.addNodeDef("ND_foo", "color3", "foo") fooInputA = nodeDef.addInput("a", "color3") fooInputB = nodeDef.addInput("b", "color3") fooOutput = nodeDef.getOutput("out") fooInputA.setValue(mx.Color3(1.0, 1.0, 0.0)) fooInputB.setValue(mx.Color3(0.8, 0.1, 0.1)) # Create an implementation graph for the nodedef performing # a multiplication of the three colors. nodeGraph = doc.addNodeGraph("IMP_foo") nodeGraph.setAttribute("nodedef", nodeDef.getName()) output = nodeGraph.addOutput(fooOutput.getName(), "color3") mult1 = nodeGraph.addNode("multiply", "mult1", "color3") in1 = mult1.addInput("in1", "color3") in1.setInterfaceName(fooInputA.getName()) in2 = mult1.addInput("in2", "color3") in2.setInterfaceName(fooInputB.getName()) output.setConnectedNode(mult1) doc.addNode("foo", "foo1", "color3") output = doc.addOutput("foo_test", "color3") output.setNodeName("foo1") output.setAttribute("output", "o") shadergen = mx_gen_osl.OslShaderGenerator.create() context = mx_gen_shader.GenContext(shadergen) context.registerSourceCodeSearchPath(searchPath) # Test complete mode context.getOptions().shaderInterfaceType = int( mx_gen_shader.ShaderInterfaceType.SHADER_INTERFACE_COMPLETE) shader = shadergen.generate(exampleName, output, context) self.assertTrue(shader) self.assertTrue( len(shader.getSourceCode(mx_gen_shader.PIXEL_STAGE)) > 0) ps = shader.getStage(mx_gen_shader.PIXEL_STAGE) uniforms = ps.getUniformBlock(mx_gen_osl.OSL_UNIFORMS) self.assertTrue(uniforms.size() == 2) outputs = ps.getOutputBlock(mx_gen_osl.OSL_OUTPUTS) self.assertTrue(outputs.size() == 1) self.assertTrue(outputs[0].getName() == output.getName()) file = open(shader.getName() + "_complete.osl", "w+") file.write(shader.getSourceCode(mx_gen_shader.PIXEL_STAGE)) file.close() os.remove(shader.getName() + "_complete.osl") context.getOptions().shaderInterfaceType = int( mx_gen_shader.ShaderInterfaceType.SHADER_INTERFACE_REDUCED) shader = shadergen.generate(exampleName, output, context) self.assertTrue(shader) self.assertTrue( len(shader.getSourceCode(mx_gen_shader.PIXEL_STAGE)) > 0) ps = shader.getStage(mx_gen_shader.PIXEL_STAGE) uniforms = ps.getUniformBlock(mx_gen_osl.OSL_UNIFORMS) self.assertTrue(uniforms.size() == 0) outputs = ps.getOutputBlock(mx_gen_osl.OSL_OUTPUTS) self.assertTrue(outputs.size() == 1) self.assertTrue(outputs[0].getName() == output.getName()) file = open(shader.getName() + "_reduced.osl", "w+") file.write(shader.getSourceCode(mx_gen_shader.PIXEL_STAGE)) file.close() os.remove(shader.getName() + "_reduced.osl")
def main(): parser = argparse.ArgumentParser( description= 'Generate shader code for each material / shader in a document.') parser.add_argument( '--path', dest='paths', action='append', nargs='+', help= 'An additional absolute search path location (e.g. "/projects/MaterialX")' ) parser.add_argument( '--library', dest='libraries', action='append', nargs='+', help= 'An additional relative path to a custom data library folder (e.g. "libraries/custom")' ) parser.add_argument( '--target', dest='target', default='glsl', help= 'Target shader generator to use (e.g. "genglsl"). Default is genglsl.') parser.add_argument( '--outputPath', dest='outputPath', help= 'File path to output shaders to. If not specified, is the location of the input document is used.' ) parser.add_argument( '--validator', dest='validator', nargs='?', const=' ', type=str, help='Name of executable to perform source code validation.') parser.add_argument('--validatorArgs', dest='validatorArgs', nargs='?', const=' ', type=str, help='Optional arguments for code validator.') parser.add_argument(dest='inputFilename', help='Filename of the input document.') opts = parser.parse_args() doc = mx.createDocument() try: mx.readFromXmlFile(doc, opts.inputFilename) except mx.ExceptionFileMissing as err: print(err) sys.exit(0) stdlib = mx.createDocument() filePath = os.path.dirname(os.path.abspath(__file__)) searchPath = mx.FileSearchPath( os.path.join(filePath, '..', '..', 'libraries')) searchPath.append(os.path.dirname(opts.inputFilename)) libraryFolders = ['libraries'] if opts.paths: for pathList in opts.paths: for path in pathList: searchPath.append(path) if opts.libraries: for libraryList in opts.libraries: for library in libraryList: libraryFolders.append(library) mx.loadLibraries(libraryFolders, searchPath, stdlib) doc.importLibrary(stdlib) valid, msg = doc.validate() if not valid: print('Validation warnings for input document:') print(msg) gentarget = 'glsl' if opts.target: gentarget = opts.target if gentarget == 'osl': shadergen = mx_gen_osl.OslShaderGenerator.create() elif gentarget == 'mdl': shadergen = mx_gen_mdl.MdlShaderGenerator.create() elif gentarget == 'essl': shadergen = mx_gen_glsl.EsslShaderGenerator.create() else: shadergen = mx_gen_glsl.GlslShaderGenerator.create() context = mx_gen_shader.GenContext(shadergen) context.registerSourceCodeSearchPath(searchPath) genoptions = context.getOptions() genoptions.shaderInterfaceType = int( mx_gen_shader.ShaderInterfaceType.SHADER_INTERFACE_COMPLETE) print('- Set up CMS ...') cms = mx_gen_shader.DefaultColorManagementSystem.create( shadergen.getTarget()) cms.loadLibrary(doc) shadergen.setColorManagementSystem(cms) print('- Set up Units ...') unitsystem = mx_gen_shader.UnitSystem.create(shadergen.getTarget()) registry = mx.UnitConverterRegistry.create() distanceTypeDef = doc.getUnitTypeDef('distance') registry.addUnitConverter(distanceTypeDef, mx.LinearUnitConverter.create(distanceTypeDef)) angleTypeDef = doc.getUnitTypeDef('angle') registry.addUnitConverter(angleTypeDef, mx.LinearUnitConverter.create(angleTypeDef)) unitsystem.loadLibrary(stdlib) unitsystem.setUnitConverterRegistry(registry) shadergen.setUnitSystem(unitsystem) genoptions.targetDistanceUnit = 'meter' # Look for shader nodes shaderNodes = mx_gen_shader.findRenderableElements(doc, False) if not shaderNodes: materials = doc.getMaterialNodes() for material in materials: shaderNodes += mx.getShaderNodes(material, mx.SURFACE_SHADER_TYPE_STRING) if not shaderNodes: shaderNodes = doc.getNodesOfType(mx.SURFACE_SHADER_TYPE_STRING) pathPrefix = '' if opts.outputPath and os.path.exists(opts.outputPath): pathPrefix = opts.outputPath + os.path.sep else: pathPrefix = os.path.dirname(os.path.abspath(opts.inputFilename)) print('- Shader output path: ' + pathPrefix) for shaderNode in shaderNodes: # Material nodes are not supported directly for generation so find upstream # shader nodes. if shaderNode.getCategory() == 'surfacematerial': shaderNodes += mx.getShaderNodes(shaderNode, mx.SURFACE_SHADER_TYPE_STRING) continue shaderNodeName = shaderNode.getName() print('-- Generate code for node: ' + shaderNodeName) shaderNodeName = mx.createValidName(shaderNodeName) shader = shadergen.generate(shaderNodeName, shaderNode, context) if shader: # Use extension of .vert and .frag as it's type is # recognized by glslangValidator if gentarget == 'glsl' or gentarget == 'essl': pixelSource = shader.getSourceCode(mx_gen_shader.PIXEL_STAGE) filename = pathPrefix + shader.getName( ) + "." + gentarget + ".frag" print('--- Wrote pixel shader to: ' + filename) file = open(filename, 'w+') file.write(pixelSource) file.close() validateCode(filename, opts.validator, opts.validatorArgs) vertexSource = shader.getSourceCode(mx_gen_shader.VERTEX_STAGE) filename = pathPrefix + shader.getName( ) + "." + gentarget + ".vert" print('--- Wrote vertex shader to: ' + filename) file = open(filename, 'w+') file.write(vertexSource) file.close() validateCode(filename, opts.validator, opts.validatorArgs) else: pixelSource = shader.getSourceCode(mx_gen_shader.PIXEL_STAGE) filename = pathPrefix + shader.getName() + "." + gentarget print('--- Wrote pixel shader to: ' + filename) file = open(filename, 'w+') file.write(pixelSource) file.close() else: print('--- Failed to generate code for: ' + shaderNode.getName())