Ejemplo n.º 1
0
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))
Ejemplo n.º 2
0
    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")
Ejemplo n.º 3
0
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())