mirror of
https://github.com/johndoe6345789/SDL3CPlusPlus.git
synced 2026-04-25 22:25:07 +00:00
stuff
This commit is contained in:
@@ -1,3 +0,0 @@
|
||||
# Python Code Examples
|
||||
|
||||
This folder contains example Python scripts that generate, process, and validate material content using the MaterialX API.
|
||||
@@ -1,72 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
'''
|
||||
Generate a baked version of each material in the input document, using the TextureBaker class in the MaterialXRenderGlsl library.
|
||||
'''
|
||||
|
||||
import sys, os, argparse
|
||||
from sys import platform
|
||||
|
||||
import MaterialX as mx
|
||||
from MaterialX import PyMaterialXRender as mx_render
|
||||
from MaterialX import PyMaterialXRenderGlsl as mx_render_glsl
|
||||
if platform == "darwin":
|
||||
from MaterialX import PyMaterialXRenderMsl as mx_render_msl
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Generate a baked version of each material in the input document.")
|
||||
parser.add_argument("--width", dest="width", type=int, default=1024, help="Specify the width of baked textures.")
|
||||
parser.add_argument("--height", dest="height", type=int, default=1024, help="Specify the height of baked textures.")
|
||||
parser.add_argument("--hdr", dest="hdr", action="store_true", help="Save images to hdr format.")
|
||||
parser.add_argument("--average", dest="average", action="store_true", help="Average baked images to generate constant values.")
|
||||
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('--writeDocumentPerMaterial', dest='writeDocumentPerMaterial', type=mx.stringToBoolean, default=True, help='Specify whether to write baked materials to seprate MaterialX documents. Default is True')
|
||||
if platform == "darwin":
|
||||
parser.add_argument("--glsl", dest="useGlslBackend", default=False, type=bool, help="Set to True to use GLSL backend (default = Metal).")
|
||||
parser.add_argument(dest="inputFilename", help="Filename of the input document.")
|
||||
parser.add_argument(dest="outputFilename", help="Filename of the output 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()
|
||||
searchPath = mx.getDefaultDataSearchPath()
|
||||
searchPath.append(os.path.dirname(opts.inputFilename))
|
||||
libraryFolders = []
|
||||
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)
|
||||
libraryFolders.extend(mx.getDefaultDataLibraryFolders())
|
||||
mx.loadLibraries(libraryFolders, searchPath, stdlib)
|
||||
doc.importLibrary(stdlib)
|
||||
|
||||
valid, msg = doc.validate()
|
||||
if not valid:
|
||||
print("Validation warnings for input document:")
|
||||
print(msg)
|
||||
|
||||
baseType = mx_render.BaseType.FLOAT if opts.hdr else mx_render.BaseType.UINT8
|
||||
|
||||
|
||||
if platform == "darwin" and not opts.useGlslBackend:
|
||||
baker = mx_render_msl.TextureBaker.create(opts.width, opts.height, baseType)
|
||||
else:
|
||||
baker = mx_render_glsl.TextureBaker.create(opts.width, opts.height, baseType)
|
||||
|
||||
if opts.average:
|
||||
baker.setAverageImages(True)
|
||||
baker.writeDocumentPerMaterial(opts.writeDocumentPerMaterial)
|
||||
baker.bakeAllMaterials(doc, searchPath, opts.outputFilename)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,268 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
'''
|
||||
Construct a MaterialX file from the textures in the given folder, using the standard data libraries
|
||||
to build a mapping from texture filenames to shader inputs.
|
||||
|
||||
By default the standard_surface shading model is assumed, with the --shadingModel option used to
|
||||
select any other shading model in the data libraries.
|
||||
'''
|
||||
|
||||
import os
|
||||
import re
|
||||
import argparse
|
||||
from difflib import SequenceMatcher
|
||||
|
||||
import MaterialX as mx
|
||||
|
||||
UDIM_TOKEN = '.<UDIM>.'
|
||||
UDIM_REGEX = r'\.\d+\.'
|
||||
TEXTURE_EXTENSIONS = [ "exr", "png", "jpg", "jpeg", "tif", "hdr" ]
|
||||
INPUT_ALIASES = { "roughness": "specular_roughness" }
|
||||
|
||||
class UdimFilePath(mx.FilePath):
|
||||
|
||||
def __init__(self, pathString):
|
||||
super().__init__(pathString)
|
||||
|
||||
self._isUdim = False
|
||||
self._udimFiles = []
|
||||
self._udimRegex = re.compile(UDIM_REGEX)
|
||||
|
||||
textureDir = self.getParentPath()
|
||||
textureName = self.getBaseName()
|
||||
textureExtension = self.getExtension()
|
||||
|
||||
if not self._udimRegex.search(textureName):
|
||||
self._udimFiles = [self]
|
||||
return
|
||||
|
||||
self._isUdim = True
|
||||
fullNamePattern = self._udimRegex.sub(self._udimRegex.pattern.replace('\\', '\\\\'),
|
||||
textureName)
|
||||
|
||||
udimFiles = filter(
|
||||
lambda f: re.search(fullNamePattern, f.asString()),
|
||||
textureDir.getFilesInDirectory(textureExtension)
|
||||
)
|
||||
self._udimFiles = [textureDir / f for f in udimFiles]
|
||||
|
||||
def __str__(self):
|
||||
return self.asPattern()
|
||||
|
||||
def asPattern(self):
|
||||
if not self._isUdim:
|
||||
return self.asString()
|
||||
|
||||
textureDir = self.getParentPath()
|
||||
textureName = self.getBaseName()
|
||||
|
||||
pattern = textureDir / mx.FilePath(
|
||||
self._udimRegex.sub(UDIM_TOKEN, textureName))
|
||||
return pattern.asString()
|
||||
|
||||
def isUdim(self):
|
||||
return self._isUdim
|
||||
|
||||
def getUdimFiles(self):
|
||||
return self._udimFiles
|
||||
|
||||
def getUdimNumbers(self):
|
||||
def _extractUdimNumber(_file):
|
||||
pattern = self._udimRegex.search(_file.getBaseName())
|
||||
if pattern:
|
||||
return re.search(r"\d+", pattern.group()).group()
|
||||
|
||||
return list(map(_extractUdimNumber, self._udimFiles))
|
||||
|
||||
def getNameWithoutExtension(self):
|
||||
if self._isUdim:
|
||||
name = self._udimRegex.split(self.getBaseName())[0]
|
||||
else:
|
||||
name = self.getBaseName().rsplit('.', 1)[0]
|
||||
|
||||
return re.sub(r'[^\w\s]+', '_', name)
|
||||
|
||||
def listTextures(textureDir, texturePrefix=None):
|
||||
'''
|
||||
Return a list of texture filenames matching known extensions.
|
||||
'''
|
||||
|
||||
texturePrefix = texturePrefix or ""
|
||||
allTextures = []
|
||||
for ext in TEXTURE_EXTENSIONS:
|
||||
textures = [textureDir / f for f in textureDir.getFilesInDirectory(ext)
|
||||
if f.asString().lower().startswith(texturePrefix.lower())]
|
||||
while textures:
|
||||
textureFile = UdimFilePath(textures[0].asString())
|
||||
allTextures.append(textureFile)
|
||||
for udimFile in textureFile.getUdimFiles():
|
||||
textures.remove(udimFile)
|
||||
return allTextures
|
||||
|
||||
def findBestMatch(textureName, shadingModel):
|
||||
'''
|
||||
Given a texture name and shading model, return the shader input that is the closest match.
|
||||
'''
|
||||
|
||||
parts = textureName.rsplit("_")
|
||||
|
||||
baseTexName = parts[-1]
|
||||
if baseTexName.lower() == 'color':
|
||||
baseTexName = ''.join(parts[-2:])
|
||||
if baseTexName in INPUT_ALIASES:
|
||||
baseTexName = INPUT_ALIASES.get(baseTexName.lower())
|
||||
|
||||
shaderInputs = shadingModel.getActiveInputs()
|
||||
ratios = []
|
||||
for shaderInput in shaderInputs:
|
||||
inputName = shaderInput.getName()
|
||||
inputName = re.sub(r'[^a-zA-Z0-9\s]', '', inputName).lower()
|
||||
baseTexName = re.sub(r'[^a-zA-Z0-9\s]', '', baseTexName).lower()
|
||||
|
||||
sequenceScore = SequenceMatcher(None, inputName, baseTexName).ratio()
|
||||
ratios.append(sequenceScore * 100)
|
||||
|
||||
highscore = max(ratios)
|
||||
if highscore < 50:
|
||||
return None
|
||||
|
||||
idx = ratios.index(highscore)
|
||||
return shaderInputs[idx]
|
||||
|
||||
def buildDocument(textureFiles, mtlxFile, shadingModel, colorspace, useTiledImage):
|
||||
'''
|
||||
Build a MaterialX document from the given textures and shading model.
|
||||
'''
|
||||
|
||||
# Find the default library nodedef, if any, for the requested shading model.
|
||||
stdlib = mx.createDocument()
|
||||
mx.loadLibraries(mx.getDefaultDataLibraryFolders(), mx.getDefaultDataSearchPath(), stdlib)
|
||||
matchingNodeDefs = stdlib.getMatchingNodeDefs(shadingModel)
|
||||
if not matchingNodeDefs:
|
||||
print('Shading model', shadingModel, 'not found in the MaterialX data libraries')
|
||||
return None
|
||||
shadingModelNodeDef = matchingNodeDefs[0]
|
||||
for nodeDef in matchingNodeDefs:
|
||||
if nodeDef.getAttribute('isdefaultversion') == 'true':
|
||||
shadingModelNodeDef = nodeDef
|
||||
|
||||
# Create content document.
|
||||
doc = mx.createDocument()
|
||||
materialName = mx.createValidName(mtlxFile.getBaseName().rsplit('.', 1)[0])
|
||||
nodeGraph = doc.addNodeGraph('NG_' + materialName)
|
||||
shaderNode = doc.addNode(shadingModel, 'SR_' + materialName, 'surfaceshader')
|
||||
doc.addMaterialNode('M_' + materialName, shaderNode)
|
||||
|
||||
# Iterate over texture files.
|
||||
imageNodeCategory = 'tiledimage' if useTiledImage else 'image'
|
||||
udimNumbers = set()
|
||||
for textureFile in textureFiles:
|
||||
textureName = textureFile.getNameWithoutExtension()
|
||||
shaderInput = findBestMatch(textureName, shadingModelNodeDef)
|
||||
|
||||
if not shaderInput:
|
||||
print('Skipping', textureFile.getBaseName(), 'which does not match any', shadingModel, 'input')
|
||||
continue
|
||||
|
||||
inputName = shaderInput.getName()
|
||||
inputType = shaderInput.getType()
|
||||
|
||||
# Skip inputs that have already been created, e.g. in multi-UDIM materials.
|
||||
if shaderNode.getInput(inputName) or nodeGraph.getChild(textureName):
|
||||
continue
|
||||
|
||||
mtlInput = shaderNode.addInput(inputName)
|
||||
textureName = nodeGraph.createValidChildName(textureName)
|
||||
imageNode = nodeGraph.addNode(imageNodeCategory, textureName, inputType)
|
||||
|
||||
# Set color space.
|
||||
if shaderInput.isColorType():
|
||||
imageNode.setColorSpace(colorspace)
|
||||
|
||||
# Set file path.
|
||||
filePathString = os.path.relpath(textureFile.asPattern(), mtlxFile.getParentPath().asString())
|
||||
imageNode.setInputValue('file', filePathString, 'filename')
|
||||
|
||||
# Apply special cases for normal maps.
|
||||
inputNode = imageNode
|
||||
connNode = imageNode
|
||||
inBetweenNodes = []
|
||||
if inputName.endswith('normal') and shadingModel == 'standard_surface':
|
||||
inBetweenNodes = ["normalmap"]
|
||||
for inNodeName in inBetweenNodes:
|
||||
connNode = nodeGraph.addNode(inNodeName, textureName + '_' + inNodeName, inputType)
|
||||
connNode.setConnectedNode('in', inputNode)
|
||||
inputNode = connNode
|
||||
|
||||
# Create output.
|
||||
outputNode = nodeGraph.addOutput(textureName + '_output', inputType)
|
||||
outputNode.setConnectedNode(connNode)
|
||||
mtlInput.setConnectedOutput(outputNode)
|
||||
mtlInput.setType(inputType)
|
||||
|
||||
if textureFile.isUdim():
|
||||
udimNumbers.update(set(textureFile.getUdimNumbers()))
|
||||
|
||||
# Create udim set
|
||||
if udimNumbers:
|
||||
geomInfoName = doc.createValidChildName('GI_' + materialName)
|
||||
geomInfo = doc.addGeomInfo(geomInfoName)
|
||||
geomInfo.setGeomPropValue('udimset', list(udimNumbers), "stringarray")
|
||||
|
||||
# Return the new document
|
||||
return doc
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--outputFilename', dest='outputFilename', type=str, help='Filename of the output MaterialX document.')
|
||||
parser.add_argument('--shadingModel', dest='shadingModel', type=str, default="standard_surface", help='The shading model used in analyzing input textures.')
|
||||
parser.add_argument('--colorSpace', dest='colorSpace', type=str, help='The colorspace in which input textures should be interpreted, defaulting to srgb_texture.')
|
||||
parser.add_argument('--texturePrefix', dest='texturePrefix', type=str, help='Filter input textures by the given prefix.')
|
||||
parser.add_argument('--tiledImage', dest='tiledImage', action="store_true", help='Request tiledimage nodes instead of image nodes.')
|
||||
parser.add_argument(dest='inputDirectory', nargs='?', help='Input folder that will be scanned for textures, defaulting to the current working directory.')
|
||||
|
||||
options = parser.parse_args()
|
||||
|
||||
texturePath = mx.FilePath.getCurrentPath()
|
||||
if options.inputDirectory:
|
||||
texturePath = mx.FilePath(options.inputDirectory)
|
||||
if not texturePath.isDirectory():
|
||||
print('Input folder not found:', texturePath)
|
||||
return
|
||||
|
||||
mtlxFile = texturePath / mx.FilePath('material.mtlx')
|
||||
if options.outputFilename:
|
||||
mtlxFile = mx.FilePath(options.outputFilename)
|
||||
|
||||
textureFiles = listTextures(texturePath, texturePrefix=options.texturePrefix)
|
||||
if not textureFiles:
|
||||
print('No matching textures found in input folder.')
|
||||
return
|
||||
|
||||
# Get shading model and color space.
|
||||
shadingModel = 'standard_surface'
|
||||
colorspace = 'srgb_texture'
|
||||
if options.shadingModel:
|
||||
shadingModel = options.shadingModel
|
||||
if options.colorSpace:
|
||||
colorspace = options.colorSpace
|
||||
print('Analyzing textures in the', texturePath.asString(), 'folder for the', shadingModel, 'shading model.')
|
||||
|
||||
# Create the MaterialX document.
|
||||
doc = buildDocument(textureFiles, mtlxFile, shadingModel, colorspace, options.tiledImage)
|
||||
if not doc:
|
||||
return
|
||||
|
||||
if options.outputFilename:
|
||||
# Write the document to disk.
|
||||
if not mtlxFile.getParentPath().exists():
|
||||
mtlxFile.getParentPath().createDirectory()
|
||||
mx.writeToXmlFile(doc, mtlxFile.asString())
|
||||
print('Wrote MaterialX document to disk:', mtlxFile.asString())
|
||||
else:
|
||||
# Print the document to the standard output.
|
||||
print('Generated MaterialX document:')
|
||||
print(mx.writeToXmlString(doc))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,208 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
'''
|
||||
Utility to generate the shader for materials found in a MaterialX document. One file will be generated
|
||||
for each material / shader found. The currently supported target languages are GLSL, OSL, MDL and ESSL.
|
||||
'''
|
||||
|
||||
import sys, os, argparse, subprocess
|
||||
|
||||
import MaterialX as mx
|
||||
import MaterialX.PyMaterialXGenGlsl as mx_gen_glsl
|
||||
import MaterialX.PyMaterialXGenMdl as mx_gen_mdl
|
||||
import MaterialX.PyMaterialXGenMsl as mx_gen_msl
|
||||
import MaterialX.PyMaterialXGenOsl as mx_gen_osl
|
||||
import MaterialX.PyMaterialXGenShader as mx_gen_shader
|
||||
|
||||
def validateCode(sourceCodeFile, codevalidator, codevalidatorArgs):
|
||||
if codevalidator:
|
||||
cmd = codevalidator.split()
|
||||
cmd.append(sourceCodeFile)
|
||||
if codevalidatorArgs:
|
||||
cmd.append(codevalidatorArgs)
|
||||
cmd_flatten ='----- Run Validator: '
|
||||
for c in cmd:
|
||||
cmd_flatten += c + ' '
|
||||
print(cmd_flatten)
|
||||
try:
|
||||
output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
|
||||
return output.decode(encoding='utf-8')
|
||||
except subprocess.CalledProcessError as out:
|
||||
return (out.output.decode(encoding='utf-8'))
|
||||
return ""
|
||||
|
||||
def getMaterialXFiles(rootPath):
|
||||
filelist = []
|
||||
if os.path.isdir(rootPath):
|
||||
for subdir, dirs, files in os.walk(rootPath):
|
||||
for file in files:
|
||||
if file.endswith('mtlx'):
|
||||
filelist.append(os.path.join(subdir, file))
|
||||
else:
|
||||
filelist.append( rootPath )
|
||||
|
||||
return filelist
|
||||
|
||||
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. "glsl, osl, mdl, essl, vulkan"). Default is glsl.')
|
||||
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('--vulkanGlsl', dest='vulkanCompliantGlsl', default=False, type=bool, help='Set to True to generate Vulkan-compliant GLSL when using the genglsl target.')
|
||||
parser.add_argument('--shaderInterfaceType', dest='shaderInterfaceType', default=0, type=int, help='Set the type of shader interface to be generated')
|
||||
parser.add_argument(dest='inputFilename', help='Path to input document or folder containing input documents.')
|
||||
opts = parser.parse_args()
|
||||
|
||||
filelist = getMaterialXFiles(opts.inputFilename)
|
||||
|
||||
for inputFilename in filelist:
|
||||
doc = mx.createDocument()
|
||||
try:
|
||||
mx.readFromXmlFile(doc, inputFilename)
|
||||
except mx.ExceptionFileMissing as err:
|
||||
print('Generation failed: "', err, '"')
|
||||
sys.exit(-1)
|
||||
|
||||
print('---------- Generate code for file: ', inputFilename, '--------------------')
|
||||
|
||||
stdlib = mx.createDocument()
|
||||
searchPath = mx.getDefaultDataSearchPath()
|
||||
searchPath.append(os.path.dirname(inputFilename))
|
||||
libraryFolders = []
|
||||
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)
|
||||
libraryFolders.extend(mx.getDefaultDataLibraryFolders())
|
||||
try:
|
||||
mx.loadLibraries(libraryFolders, searchPath, stdlib)
|
||||
doc.importLibrary(stdlib)
|
||||
except Exception as err:
|
||||
print('Generation failed: "', err, '"')
|
||||
sys.exit(-1)
|
||||
|
||||
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()
|
||||
elif gentarget == 'vulkan':
|
||||
shadergen = mx_gen_glsl.VkShaderGenerator.create()
|
||||
elif gentarget == 'msl':
|
||||
shadergen = mx_gen_msl.MslShaderGenerator.create()
|
||||
else:
|
||||
shadergen = mx_gen_glsl.GlslShaderGenerator.create()
|
||||
|
||||
context = mx_gen_shader.GenContext(shadergen)
|
||||
context.registerSourceCodeSearchPath(searchPath)
|
||||
|
||||
# If we're generating Vulkan-compliant GLSL then set the binding context
|
||||
if opts.vulkanCompliantGlsl:
|
||||
bindingContext = mx_gen_glsl.GlslResourceBindingContext.create(0,0)
|
||||
context.pushUserData('udbinding', bindingContext)
|
||||
|
||||
genoptions = context.getOptions()
|
||||
if opts.shaderInterfaceType == 0 or opts.shaderInterfaceType == 1:
|
||||
genoptions.shaderInterfaceType = mx_gen_shader.ShaderInterfaceType(opts.shaderInterfaceType)
|
||||
else:
|
||||
genoptions.shaderInterfaceType = 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 renderable nodes
|
||||
nodes = mx_gen_shader.findRenderableElements(doc)
|
||||
if not nodes:
|
||||
nodes = doc.getMaterialNodes()
|
||||
if not nodes:
|
||||
nodes = 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(inputFilename))
|
||||
print('- Shader output path: ' + pathPrefix)
|
||||
|
||||
failedShaders = ""
|
||||
for node in nodes:
|
||||
nodeName = node.getName()
|
||||
print('-- Generate code for node: ' + nodeName)
|
||||
nodeName = mx.createValidName(nodeName)
|
||||
shader = shadergen.generate(nodeName, node, context)
|
||||
if shader:
|
||||
# Use extension of .vert and .frag as it's type is
|
||||
# recognized by glslangValidator
|
||||
if gentarget in ['glsl', 'essl', 'vulkan', 'msl']:
|
||||
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()
|
||||
errors = 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()
|
||||
errors += 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()
|
||||
errors = validateCode(filename, opts.validator, opts.validatorArgs)
|
||||
|
||||
if errors != "":
|
||||
print("--- Validation failed for node: ", nodeName)
|
||||
print("----------------------------")
|
||||
print('--- Error log: ', errors)
|
||||
print("----------------------------")
|
||||
failedShaders += (nodeName + ' ')
|
||||
else:
|
||||
print("--- Validation passed for node:", nodeName)
|
||||
|
||||
else:
|
||||
print("--- Validation failed for node:", nodeName)
|
||||
failedShaders += (nodeName + ' ')
|
||||
|
||||
if failedShaders != "":
|
||||
sys.exit(-1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,113 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
'''
|
||||
Print markdown documentation for each nodedef in the given document.
|
||||
'''
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
import MaterialX as mx
|
||||
|
||||
HEADERS = ('Name', 'Type', 'Default Value',
|
||||
'UI name', 'UI min', 'UI max', 'UI Soft Min', 'UI Soft Max', 'UI step', 'UI group', 'UI Advanced', 'Doc', 'Uniform')
|
||||
|
||||
ATTR_NAMES = ('uiname', 'uimin', 'uimax', 'uisoftmin', 'uisoftmax', 'uistep', 'uifolder', 'uiadvanced', 'doc', 'uniform' )
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Print documentation for each nodedef in the given document.")
|
||||
parser.add_argument(dest="inputFilename", help="Filename of the input MaterialX document.")
|
||||
parser.add_argument('--docType', dest='documentType', default='md', help='Document type. Default is "md" (Markdown). Specify "html" for HTML output')
|
||||
parser.add_argument('--showInherited', default=False, action='store_true', help='Show inherited inputs. Default is False')
|
||||
opts = parser.parse_args()
|
||||
|
||||
doc = mx.createDocument()
|
||||
try:
|
||||
mx.readFromXmlFile(doc, opts.inputFilename)
|
||||
except mx.ExceptionFileMissing as err:
|
||||
print(err)
|
||||
sys.exit(0)
|
||||
|
||||
for nd in doc.getNodeDefs():
|
||||
# HTML output
|
||||
if opts.documentType == "html":
|
||||
print('<head><style>')
|
||||
print('table, th, td {')
|
||||
print(' border-bottom: 1px solid; border-collapse: collapse; padding: 10px;')
|
||||
print('}')
|
||||
print('</style></head>')
|
||||
print('<ul>')
|
||||
print('<li> <em>Nodedef</em>: %s' % nd.getName())
|
||||
print('<li> <em>Type</em>: %s' % nd.getType())
|
||||
if len(nd.getNodeGroup()) > 0:
|
||||
print('<li> <em>Node Group</em>: %s' % nd.getNodeGroup())
|
||||
if len(nd.getVersionString()) > 0:
|
||||
print('<li> <em>Version</em>: %s. Is default: %s' % (nd.getVersionString(), nd.getDefaultVersion()))
|
||||
if len(nd.getInheritString()) > 0:
|
||||
print('<li> <em>Inherits From</em>: %s' % nd.getInheritString())
|
||||
print('<li> <em>Doc</em>: %s\n' % nd.getAttribute('doc'))
|
||||
print('</ul>')
|
||||
print('<table><tr>')
|
||||
for h in HEADERS:
|
||||
print('<th>' + h + '</th>')
|
||||
print('</tr>')
|
||||
inputList = nd.getActiveInputs() if opts.showInherited else nd.getInputs()
|
||||
tokenList = nd.getActiveTokens() if opts.showInherited else nd.getTokens()
|
||||
outputList = nd.getActiveOutputs() if opts.showInherited else nd.getOutputs()
|
||||
totalList = inputList + tokenList + outputList;
|
||||
for port in totalList:
|
||||
print('<tr>')
|
||||
infos = []
|
||||
if port in outputList:
|
||||
infos.append('<em>'+ port.getName() + '</em>')
|
||||
elif port in tokenList:
|
||||
infos.append(port.getName())
|
||||
else:
|
||||
infos.append('<b>'+ port.getName() + '</b>')
|
||||
infos.append(port.getType())
|
||||
val = port.getValue()
|
||||
if port.getType() == "float":
|
||||
val = round(val, 6)
|
||||
infos.append(str(val))
|
||||
for attrname in ATTR_NAMES:
|
||||
infos.append(port.getAttribute(attrname))
|
||||
for info in infos:
|
||||
print('<td>' + info + '</td>')
|
||||
print('</tr>')
|
||||
print('</table>')
|
||||
|
||||
# Markdown output
|
||||
else:
|
||||
print('- *Nodedef*: %s' % nd.getName())
|
||||
print('- *Type*: %s' % nd.getType())
|
||||
if len(nd.getNodeGroup()) > 0:
|
||||
print('- *Node Group*: %s' % nd.getNodeGroup())
|
||||
if len(nd.getVersionString()) > 0:
|
||||
print('- *Version*: %s. Is default: %s' % (nd.getVersionString(), nd.getDefaultVersion()))
|
||||
if len(nd.getInheritString()) > 0:
|
||||
print('- *Inherits From*: %s' % nd.getInheritString())
|
||||
print('- *Doc*: %s\n' % nd.getAttribute('doc'))
|
||||
print('| ' + ' | '.join(HEADERS) + ' |')
|
||||
print('|' + ' ---- |' * len(HEADERS) + '')
|
||||
inputList = nd.getActiveInputs() if opts.showInherited else nd.getInputs()
|
||||
tokenList = nd.getActiveTokens() if opts.showInherited else nd.getTokens()
|
||||
outputList = nd.getActiveOutputs() if opts.showInherited else nd.getOutputs()
|
||||
totalList = inputList + tokenList + outputList;
|
||||
for port in totalList:
|
||||
infos = []
|
||||
if port in outputList:
|
||||
infos.append('*'+ port.getName() + '*')
|
||||
elif port in tokenList:
|
||||
infos.append(port.getName())
|
||||
else:
|
||||
infos.append('**'+ port.getName() + '**')
|
||||
infos.append(port.getType())
|
||||
val = port.getValue()
|
||||
if port.getType() == "float":
|
||||
val = round(val, 6)
|
||||
infos.append(str(val))
|
||||
for attrname in ATTR_NAMES:
|
||||
infos.append(port.getAttribute(attrname))
|
||||
print('| ' + " | ".join(infos) + ' |')
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,65 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
'''
|
||||
Reformat a folder of MaterialX documents in place, optionally upgrading
|
||||
the documents to the latest version of the standard.
|
||||
'''
|
||||
|
||||
import argparse
|
||||
import os
|
||||
|
||||
import MaterialX as mx
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Reformat a folder of MaterialX documents in place.")
|
||||
parser.add_argument("--yes", dest="yes", action="store_true", help="Proceed without asking for confirmation from the user.")
|
||||
parser.add_argument('--upgrade', dest='upgrade', action="store_true", help='Upgrade documents to the latest version of the standard.')
|
||||
parser.add_argument(dest="inputFolder", help="An input folder to scan for MaterialX documents.")
|
||||
opts = parser.parse_args()
|
||||
|
||||
validDocs = dict()
|
||||
for root, dirs, files in os.walk(opts.inputFolder):
|
||||
for file in files:
|
||||
if file.endswith('.mtlx'):
|
||||
filename = os.path.join(root, file)
|
||||
doc = mx.createDocument()
|
||||
try:
|
||||
readOptions = mx.XmlReadOptions()
|
||||
readOptions.readComments = True
|
||||
readOptions.readNewlines = True
|
||||
readOptions.upgradeVersion = opts.upgrade
|
||||
try:
|
||||
mx.readFromXmlFile(doc, filename, mx.FileSearchPath(), readOptions)
|
||||
except Exception as err:
|
||||
print('Skipping "' + file + '" due to exception: ' + str(err))
|
||||
continue
|
||||
validDocs[filename] = doc
|
||||
except mx.Exception:
|
||||
pass
|
||||
|
||||
if not validDocs:
|
||||
print('No MaterialX documents were found in "%s"' % (opts.inputFolder))
|
||||
return
|
||||
|
||||
print('Found %s MaterialX files in "%s"' % (len(validDocs), opts.inputFolder))
|
||||
|
||||
mxVersion = mx.getVersionIntegers()
|
||||
|
||||
if not opts.yes:
|
||||
if opts.upgrade:
|
||||
question = 'Would you like to upgrade all %i documents to MaterialX v%i.%i in place (y/n)?' % (len(validDocs), mxVersion[0], mxVersion[1])
|
||||
else:
|
||||
question = 'Would you like to reformat all %i documents in place (y/n)?' % len(validDocs)
|
||||
answer = input(question)
|
||||
if answer != 'y' and answer != 'Y':
|
||||
return
|
||||
|
||||
for (filename, doc) in validDocs.items():
|
||||
mx.writeToXmlFile(doc, filename)
|
||||
|
||||
if opts.upgrade:
|
||||
print('Upgraded %i documents to MaterialX v%i.%i' % (len(validDocs), mxVersion[0], mxVersion[1]))
|
||||
else:
|
||||
print('Reformatted %i documents ' % len(validDocs))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,359 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
'''
|
||||
Verify that the given file is a valid MaterialX document.
|
||||
'''
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
import MaterialX as mx
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Verify that the given file is a valid MaterialX document.")
|
||||
parser.add_argument("--resolve", dest="resolve", action="store_true", help="Resolve inheritance and string substitutions.")
|
||||
parser.add_argument("--verbose", dest="verbose", action="store_true", help="Print summary of elements found in the document.")
|
||||
parser.add_argument("--stdlib", dest="stdlib", action="store_true", help="Import standard MaterialX libraries into the document.")
|
||||
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)
|
||||
|
||||
if opts.stdlib:
|
||||
stdlib = mx.createDocument()
|
||||
try:
|
||||
mx.loadLibraries(mx.getDefaultDataLibraryFolders(), mx.getDefaultDataSearchPath(), stdlib)
|
||||
except Exception as err:
|
||||
print(err)
|
||||
sys.exit(0)
|
||||
doc.importLibrary(stdlib)
|
||||
|
||||
(valid, message) = doc.validate()
|
||||
if (valid):
|
||||
print("%s is a valid MaterialX document in v%s" % (opts.inputFilename, mx.getVersionString()))
|
||||
else:
|
||||
print("%s is not a valid MaterialX document in v%s" % (opts.inputFilename, mx.getVersionString()))
|
||||
print(message)
|
||||
|
||||
if opts.verbose:
|
||||
nodegraphs = doc.getNodeGraphs()
|
||||
materials = doc.getMaterialNodes()
|
||||
looks = doc.getLooks()
|
||||
lookgroups = doc.getLookGroups()
|
||||
collections = doc.getCollections()
|
||||
nodedefs = doc.getNodeDefs()
|
||||
implementations = doc.getImplementations()
|
||||
geominfos = doc.getGeomInfos()
|
||||
geompropdefs = doc.getGeomPropDefs()
|
||||
typedefs = doc.getTypeDefs()
|
||||
propsets = doc.getPropertySets()
|
||||
variantsets = doc.getVariantSets()
|
||||
backdrops = doc.getBackdrops()
|
||||
|
||||
print("----------------------------------")
|
||||
print("Document Version: {}.{:02d}".format(*doc.getVersionIntegers()))
|
||||
print("%4d Custom Type%s%s" % (len(typedefs), pl(typedefs), listContents(typedefs, opts.resolve)))
|
||||
print("%4d Custom GeomProp%s%s" % (len(geompropdefs), pl(geompropdefs), listContents(geompropdefs, opts.resolve)))
|
||||
print("%4d NodeDef%s%s" % (len(nodedefs), pl(nodedefs), listContents(nodedefs, opts.resolve)))
|
||||
print("%4d Implementation%s%s" % (len(implementations), pl(implementations), listContents(implementations, opts.resolve)))
|
||||
print("%4d Nodegraph%s%s" % (len(nodegraphs), pl(nodegraphs), listContents(nodegraphs, opts.resolve)))
|
||||
print("%4d VariantSet%s%s" % (len(variantsets), pl(variantsets), listContents(variantsets, opts.resolve)))
|
||||
print("%4d Material%s%s" % (len(materials), pl(materials), listContents(materials, opts.resolve)))
|
||||
print("%4d Collection%s%s" % (len(collections), pl(collections), listContents(collections, opts.resolve)))
|
||||
print("%4d GeomInfo%s%s" % (len(geominfos), pl(geominfos), listContents(geominfos, opts.resolve)))
|
||||
print("%4d PropertySet%s%s" % (len(propsets), pl(propsets), listContents(propsets, opts.resolve)))
|
||||
print("%4d Look%s%s" % (len(looks), pl(looks), listContents(looks, opts.resolve)))
|
||||
print("%4d LookGroup%s%s" % (len(lookgroups), pl(lookgroups), listContents(lookgroups, opts.resolve)))
|
||||
print("%4d Top-level backdrop%s%s" % (len(backdrops), pl(backdrops), listContents(backdrops, opts.resolve)))
|
||||
print("----------------------------------")
|
||||
|
||||
def listContents(elemlist, resolve):
|
||||
if len(elemlist) == 0:
|
||||
return ''
|
||||
names = []
|
||||
for elem in elemlist:
|
||||
|
||||
if elem.isA(mx.NodeDef):
|
||||
outtype = elem.getType()
|
||||
outs = ""
|
||||
if outtype == "multioutput":
|
||||
for ot in elem.getOutputs():
|
||||
outs = outs + \
|
||||
'\n\t %s output "%s"' % (ot.getType(), ot.getName())
|
||||
names.append('%s %s "%s"%s' %
|
||||
(outtype, elem.getNodeString(), elem.getName(), outs))
|
||||
names.append(listNodedefInterface(elem))
|
||||
|
||||
elif elem.isA(mx.Implementation):
|
||||
impl = elem.getName()
|
||||
targs = []
|
||||
if elem.hasTarget():
|
||||
targs.append("target %s" % elem.getTarget())
|
||||
if targs:
|
||||
impl = "%s (%s)" % (impl, ", ".join(targs))
|
||||
if elem.hasFunction():
|
||||
if elem.hasFile():
|
||||
impl = "%s [%s:%s()]" % (
|
||||
impl, elem.getFile(), elem.getFunction())
|
||||
else:
|
||||
impl = "%s [function %s()]" % (impl, elem.getFunction())
|
||||
elif elem.hasFile():
|
||||
impl = "%s [%s]" % (impl, elem.getFile())
|
||||
names.append(impl)
|
||||
|
||||
elif elem.isA(mx.Backdrop):
|
||||
names.append('%s: contains "%s"' %
|
||||
(elem.getName(), elem.getContainsString()))
|
||||
|
||||
elif elem.isA(mx.NodeGraph):
|
||||
nchildnodes = len(elem.getChildren()) - elem.getOutputCount()
|
||||
backdrops = elem.getBackdrops()
|
||||
nbackdrops = len(backdrops)
|
||||
outs = ""
|
||||
if nbackdrops > 0:
|
||||
for bd in backdrops:
|
||||
outs = outs + '\n\t backdrop "%s"' % (bd.getName())
|
||||
outs = outs + ' contains "%s"' % bd.getContainsString()
|
||||
if elem.getOutputCount() > 0:
|
||||
for ot in elem.getOutputs():
|
||||
outs = outs + '\n\t %s output "%s"' % (ot.getType(), ot.getName())
|
||||
outs = outs + traverseInputs(ot, "", 0)
|
||||
nd = elem.getNodeDef()
|
||||
if nd:
|
||||
names.append('%s (implementation for nodedef "%s"): %d nodes%s' % (
|
||||
elem.getName(), nd.getName(), nchildnodes, outs))
|
||||
else:
|
||||
names.append("%s: %d nodes, %d backdrop%s%s" % (
|
||||
elem.getName(), nchildnodes, nbackdrops, pl(backdrops), outs))
|
||||
|
||||
elif elem.isA(mx.Node, mx.SURFACE_MATERIAL_NODE_STRING):
|
||||
shaders = mx.getShaderNodes(elem)
|
||||
names.append("%s: %d connected shader node%s" % (elem.getName(), len(shaders), pl(shaders)))
|
||||
for shader in shaders:
|
||||
names.append('Shader node "%s" (%s), with bindings:%s' % (shader.getName(), shader.getCategory(), listShaderBindings(shader)))
|
||||
|
||||
elif elem.isA(mx.GeomInfo):
|
||||
props = elem.getGeomProps()
|
||||
if props:
|
||||
propnames = " (Geomprops: " + ", ".join(map(
|
||||
lambda x: "%s=%s" % (x.getName(), getConvertedValue(x)), props)) + ")"
|
||||
else:
|
||||
propnames = ""
|
||||
|
||||
tokens = elem.getTokens()
|
||||
if tokens:
|
||||
tokennames = " (Tokens: " + ", ".join(map(
|
||||
lambda x: "%s=%s" % (x.getName(), x.getValueString()), tokens)) + ")"
|
||||
else:
|
||||
tokennames = ""
|
||||
names.append("%s%s%s" % (elem.getName(), propnames, tokennames))
|
||||
|
||||
elif elem.isA(mx.VariantSet):
|
||||
vars = elem.getVariants()
|
||||
if vars:
|
||||
varnames = " (variants " + ", ".join(map(
|
||||
lambda x: '"' + x.getName()+'"', vars)) + ")"
|
||||
else:
|
||||
varnames = ""
|
||||
names.append("%s%s" % (elem.getName(), varnames))
|
||||
|
||||
elif elem.isA(mx.PropertySet):
|
||||
props = elem.getProperties()
|
||||
if props:
|
||||
propnames = " (" + ", ".join(map(
|
||||
lambda x: "%s %s%s" % (x.getType(), x.getName(), getTarget(x)), props)) + ")"
|
||||
else:
|
||||
propnames = ""
|
||||
names.append("%s%s" % (elem.getName(), propnames))
|
||||
|
||||
elif elem.isA(mx.LookGroup):
|
||||
lks = elem.getLooks()
|
||||
if lks:
|
||||
names.append("%s (looks: %s)" % (elem.getName(), lks))
|
||||
else:
|
||||
names.append("%s (no looks)" % (elem.getName()))
|
||||
|
||||
elif elem.isA(mx.Look):
|
||||
mas = ""
|
||||
if resolve:
|
||||
mtlassns = elem.getActiveMaterialAssigns()
|
||||
else:
|
||||
mtlassns = elem.getMaterialAssigns()
|
||||
for mtlassn in mtlassns:
|
||||
mas = mas + "\n\t MaterialAssign %s to%s" % (
|
||||
mtlassn.getMaterial(), getGeoms(mtlassn, resolve))
|
||||
pas = ""
|
||||
if resolve:
|
||||
propassns = elem.getActivePropertyAssigns()
|
||||
else:
|
||||
propassns = elem.getPropertyAssigns()
|
||||
for propassn in propassns:
|
||||
propertyname = propassn.getAttribute("property")
|
||||
pas = pas + "\n\t PropertyAssign %s %s to%s" % (
|
||||
propassn.getType(), propertyname, getGeoms(propassn, resolve))
|
||||
|
||||
psas = ""
|
||||
if resolve:
|
||||
propsetassns = elem.getActivePropertySetAssigns()
|
||||
else:
|
||||
propsetassns = elem.getPropertySetAssigns()
|
||||
for propsetassn in propsetassns:
|
||||
propertysetname = propsetassn.getAttribute("propertyset")
|
||||
psas = psas + "\n\t PropertySetAssign %s to%s" % (
|
||||
propertysetname, getGeoms(propsetassn, resolve))
|
||||
|
||||
varas = ""
|
||||
if resolve:
|
||||
variantassns = elem.getActiveVariantAssigns()
|
||||
else:
|
||||
variantassns = elem.getVariantAssigns()
|
||||
for varassn in variantassns:
|
||||
varas = varas + "\n\t VariantAssign %s from variantset %s" % (
|
||||
varassn.getVariantString(), varassn.getVariantSetString())
|
||||
|
||||
visas = ""
|
||||
if resolve:
|
||||
visassns = elem.getActiveVisibilities()
|
||||
else:
|
||||
visassns = elem.getVisibilities()
|
||||
for vis in visassns:
|
||||
visstr = 'on' if vis.getVisible() else 'off'
|
||||
visas = visas + "\n\t Set %s visibility%s %s to%s" % (
|
||||
vis.getVisibilityType(), getViewerGeoms(vis), visstr, getGeoms(vis, resolve))
|
||||
|
||||
names.append("%s%s%s%s%s%s" %
|
||||
(elem.getName(), mas, pas, psas, varas, visas))
|
||||
|
||||
else:
|
||||
names.append(elem.getName())
|
||||
return ":\n\t" + "\n\t".join(names)
|
||||
|
||||
def listShaderBindings(shader):
|
||||
s = ''
|
||||
for inp in shader.getInputs():
|
||||
bname = inp.getName()
|
||||
btype = inp.getType()
|
||||
if inp.hasOutputString():
|
||||
outname = inp.getOutputString()
|
||||
if inp.hasNodeGraphString():
|
||||
ngname = inp.getNodeGraphString()
|
||||
s = s + '\n\t %s "%s" -> nodegraph "%s" output "%s"' % (btype, bname, ngname, outname)
|
||||
else:
|
||||
s = s + '\n\t %s "%s" -> output "%s"' % (btype, bname, outname)
|
||||
else:
|
||||
bval = getConvertedValue(inp)
|
||||
s = s + '\n\t %s "%s" = %s' % (btype, bname, bval)
|
||||
return s
|
||||
|
||||
def listNodedefInterface(nodedef):
|
||||
s = ''
|
||||
for inp in nodedef.getActiveInputs():
|
||||
iname = inp.getName()
|
||||
itype = inp.getType()
|
||||
if s:
|
||||
s = s + '\n\t'
|
||||
s = s + ' %s input "%s"' % (itype, iname)
|
||||
for tok in nodedef.getActiveTokens():
|
||||
tname = tok.getName()
|
||||
ttype = tok.getType()
|
||||
if s:
|
||||
s = s + '\n\t'
|
||||
s = s + ' %s token "%s"' % (ttype, tname)
|
||||
return s
|
||||
|
||||
def traverseInputs(node, port, depth):
|
||||
s = ''
|
||||
if node.isA(mx.Output):
|
||||
parent = node.getConnectedNode()
|
||||
s = s + traverseInputs(parent, "", depth+1)
|
||||
else:
|
||||
s = s + '%s%s -> %s %s "%s"' % (spc(depth), port,
|
||||
node.getType(), node.getCategory(), node.getName())
|
||||
ins = node.getActiveInputs()
|
||||
for i in ins:
|
||||
if i.hasInterfaceName():
|
||||
intname = i.getInterfaceName()
|
||||
s = s + \
|
||||
'%s%s ^- %s interface "%s"' % (spc(depth+1),
|
||||
i.getName(), i.getType(), intname)
|
||||
elif i.hasValueString():
|
||||
val = getConvertedValue(i)
|
||||
s = s + \
|
||||
'%s%s = %s value %s' % (
|
||||
spc(depth+1), i.getName(), i.getType(), val)
|
||||
else:
|
||||
parent = i.getConnectedNode()
|
||||
if parent:
|
||||
s = s + traverseInputs(parent, i.getName(), depth+1)
|
||||
toks = node.getActiveTokens()
|
||||
for i in toks:
|
||||
if i.hasInterfaceName():
|
||||
intname = i.getInterfaceName()
|
||||
s = s + \
|
||||
'%s[T]%s ^- %s interface "%s"' % (
|
||||
spc(depth+1), i.getName(), i.getType(), intname)
|
||||
elif i.hasValueString():
|
||||
val = i.getValueString()
|
||||
s = s + \
|
||||
'%s[T]%s = %s value "%s"' % (
|
||||
spc(depth+1), i.getName(), i.getType(), val)
|
||||
else:
|
||||
s = s + \
|
||||
'%s[T]%s error: no valueString' % (
|
||||
spc(depth+1), i.getName())
|
||||
return s
|
||||
|
||||
def pl(elem):
|
||||
if len(elem) == 1:
|
||||
return ""
|
||||
else:
|
||||
return "s"
|
||||
|
||||
def spc(depth):
|
||||
return "\n\t " + ": "*depth
|
||||
|
||||
# Return a value string for the element, converting units if appropriate
|
||||
def getConvertedValue(elem):
|
||||
if elem.getType() in ["float", "vector2", "vector3", "vector4"]:
|
||||
if elem.hasUnit():
|
||||
u = elem.getUnit()
|
||||
print ("[Unit for %s is %s]" % (elem.getName(), u))
|
||||
if elem.hasUnitType():
|
||||
utype = elem.getUnitType()
|
||||
print ("[Unittype for %s is %s]" % (elem.getName(), utype))
|
||||
# NOTDONE...
|
||||
return elem.getValueString()
|
||||
|
||||
def getGeoms(elem, resolve):
|
||||
s = ""
|
||||
if elem.hasGeom():
|
||||
if resolve:
|
||||
s = s + ' geom "%s"' % elem.getActiveGeom()
|
||||
else:
|
||||
s = s + ' geom "%s"' % elem.getGeom()
|
||||
if elem.hasCollectionString():
|
||||
s = s + ' collection "%s"' % elem.getCollectionString()
|
||||
return s
|
||||
|
||||
def getViewerGeoms(elem):
|
||||
s = ""
|
||||
if elem.hasViewerGeom():
|
||||
s = s + ' viewergeom "%s"' % elem.getViewerGeom()
|
||||
if elem.hasViewerCollection():
|
||||
s = s + ' viewercollection "%s"' % elem.getViewerCollection()
|
||||
if s:
|
||||
s = " of" + s
|
||||
return s
|
||||
|
||||
def getTarget(elem):
|
||||
if elem.hasTarget():
|
||||
return ' [target "%s"]' % elem.getTarget()
|
||||
else:
|
||||
return ""
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,101 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
'''
|
||||
Generate a baked translated version of each material in the input document, using the ShaderTranslator class in the MaterialXShaderGen library
|
||||
and the TextureBaker class in the MaterialXRenderGlsl library.
|
||||
'''
|
||||
|
||||
import sys, os, argparse
|
||||
from sys import platform
|
||||
|
||||
import MaterialX as mx
|
||||
from MaterialX import PyMaterialXGenShader as mx_gen_shader
|
||||
from MaterialX import PyMaterialXRender as mx_render
|
||||
from MaterialX import PyMaterialXRenderGlsl as mx_render_glsl
|
||||
if platform == "darwin":
|
||||
from MaterialX import PyMaterialXRenderMsl as mx_render_msl
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Generate a translated baked version of each material in the input document.")
|
||||
parser.add_argument("--width", dest="width", type=int, default=0, help="Specify an optional width for baked textures (defaults to the maximum image height in the source document).")
|
||||
parser.add_argument("--height", dest="height", type=int, default=0, help="Specify an optional height for baked textures (defaults to the maximum image width in the source document).")
|
||||
parser.add_argument("--hdr", dest="hdr", action="store_true", help="Bake images with high dynamic range (e.g. in HDR or EXR format).")
|
||||
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('--writeDocumentPerMaterial', dest='writeDocumentPerMaterial', type=mx.stringToBoolean, default=True, help='Specify whether to write baked materials to seprate MaterialX documents. Default is True')
|
||||
if platform == "darwin":
|
||||
parser.add_argument("--glsl", dest="useGlslBackend", default=False, type=bool, help="Set to True to use GLSL backend (default = Metal).")
|
||||
|
||||
parser.add_argument(dest="inputFilename", help="Filename of the input document.")
|
||||
parser.add_argument(dest="outputFilename", help="Filename of the output document.")
|
||||
parser.add_argument(dest="destShader", help="Destination shader for translation")
|
||||
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()
|
||||
searchPath = mx.getDefaultDataSearchPath()
|
||||
searchPath.append(os.path.dirname(opts.inputFilename))
|
||||
libraryFolders = []
|
||||
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)
|
||||
libraryFolders.extend(mx.getDefaultDataLibraryFolders())
|
||||
mx.loadLibraries(libraryFolders, searchPath, stdlib)
|
||||
doc.importLibrary(stdlib)
|
||||
|
||||
valid, msg = doc.validate()
|
||||
if not valid:
|
||||
print("Validation warnings for input document:")
|
||||
print(msg)
|
||||
|
||||
# Check the document for a UDIM set.
|
||||
udimSetValue = doc.getGeomPropValue(mx.UDIM_SET_PROPERTY)
|
||||
udimSet = udimSetValue.getData() if udimSetValue else []
|
||||
|
||||
# Compute baking resolution from the source document.
|
||||
imageHandler = mx_render.ImageHandler.create(mx_render.StbImageLoader.create())
|
||||
imageHandler.setSearchPath(searchPath)
|
||||
if udimSet:
|
||||
resolver = doc.createStringResolver()
|
||||
resolver.setUdimString(udimSet[0])
|
||||
imageHandler.setFilenameResolver(resolver)
|
||||
imageVec = imageHandler.getReferencedImages(doc)
|
||||
bakeWidth, bakeHeight = mx_render.getMaxDimensions(imageVec)
|
||||
|
||||
# Apply baking resolution settings.
|
||||
if opts.width > 0:
|
||||
bakeWidth = opts.width
|
||||
if opts.height > 0:
|
||||
bakeHeight = opts.height
|
||||
bakeWidth = max(bakeWidth, 4)
|
||||
bakeHeight = max(bakeHeight, 4)
|
||||
|
||||
# Translate materials between shading models
|
||||
translator = mx_gen_shader.ShaderTranslator.create()
|
||||
try:
|
||||
translator.translateAllMaterials(doc, opts.destShader)
|
||||
except mx.Exception as err:
|
||||
print(err)
|
||||
sys.exit(0)
|
||||
|
||||
# Bake translated materials to flat textures.
|
||||
baseType = mx_render.BaseType.FLOAT if opts.hdr else mx_render.BaseType.UINT8
|
||||
if platform == "darwin" and not opts.useGlslBackend:
|
||||
baker = mx_render_msl.TextureBaker.create(bakeWidth, bakeHeight, baseType)
|
||||
else:
|
||||
baker = mx_render_glsl.TextureBaker.create(bakeWidth, bakeHeight, baseType)
|
||||
baker.writeDocumentPerMaterial(opts.writeDocumentPerMaterial)
|
||||
baker.bakeAllMaterials(doc, searchPath, opts.outputFilename)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,138 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
'''
|
||||
Generate the "NodeGraphs.mtlx" example file programmatically.
|
||||
'''
|
||||
|
||||
import MaterialX as mx
|
||||
|
||||
def main():
|
||||
doc = mx.createDocument()
|
||||
|
||||
#
|
||||
# Nodegraph example 1
|
||||
#
|
||||
ng1 = doc.addNodeGraph("NG_example1")
|
||||
img1 = ng1.addNode("image", "img1", "color3")
|
||||
# Because filenames look like string types, it is necessary to explicitly declare
|
||||
# this parameter value as type "filename".
|
||||
img1.setInputValue("file", "layer1.tif", "filename")
|
||||
|
||||
img2 = ng1.addNode("image", "img2", "color3")
|
||||
img2.setInputValue("file", "layer2.tif", "filename")
|
||||
|
||||
img3 = ng1.addNode("image", "img3", "float")
|
||||
img3.setInputValue("file", "mask1.tif", "filename")
|
||||
|
||||
n0 = ng1.addNode("mix", "n0", "color3")
|
||||
# To connect an input to another node, you must first add the input with the expected
|
||||
# type, and then setConnectedNode() that input to the desired Node object.
|
||||
infg = n0.addInput("fg", "color3")
|
||||
infg.setConnectedNode(img1)
|
||||
inbg = n0.addInput("bg", "color3")
|
||||
inbg.setConnectedNode(img2)
|
||||
inmx = n0.addInput("mix", "float")
|
||||
inmx.setConnectedNode(img3)
|
||||
|
||||
n1 = ng1.addNode("multiply", "n1", "color3")
|
||||
inp1 = n1.addInput("in1", "color3")
|
||||
inp1.setConnectedNode(n0)
|
||||
inp2 = n1.setInputValue("in2", 0.22)
|
||||
|
||||
nout = ng1.addOutput("diffuse", "color3")
|
||||
nout.setConnectedNode(n1)
|
||||
|
||||
#
|
||||
# Nodegraph example 3
|
||||
#
|
||||
ng3 = doc.addNodeGraph("NG_example3")
|
||||
|
||||
img1 = ng3.addNode("image", "img1", "color3")
|
||||
img1.setInputValue("file", "<diff_albedo>", "filename")
|
||||
|
||||
img2 = ng3.addNode("image", "img2", "color3")
|
||||
img2.setInputValue("file", "<dirt_albedo>", "filename")
|
||||
|
||||
img3 = ng3.addNode("image", "img3", "float")
|
||||
img3.setInputValue("file", "<areamask>", "filename")
|
||||
|
||||
img4 = ng3.addNode("image", "img4", "float")
|
||||
img4.setInputValue("file", "<noisemask>", "filename")
|
||||
|
||||
n5 = ng3.addNode("constant", "n5", "color3")
|
||||
# For colorN, vectorN or matrix types, use the appropriate mx Type constructor.
|
||||
n5.setInputValue("value", mx.Color3(0.8,1.0,1.3))
|
||||
|
||||
n6 = ng3.addNode("multiply", "n6", "color3")
|
||||
inp1 = n6.addInput("in1", "color3")
|
||||
inp1.setConnectedNode(n5)
|
||||
inp2 = n6.addInput("in2", "color3")
|
||||
inp2.setConnectedNode(img1)
|
||||
|
||||
n7 = ng3.addNode("contrast", "n7", "color3")
|
||||
inp = n7.addInput("in", "color3")
|
||||
inp.setConnectedNode(img2)
|
||||
n7.setInputValue("amount", 0.2)
|
||||
n7.setInputValue("pivot", 0.5)
|
||||
|
||||
n8 = ng3.addNode("mix", "n8", "color3")
|
||||
infg = n8.addInput("fg", "color3")
|
||||
infg.setConnectedNode(n7)
|
||||
inbg = n8.addInput("bg", "color3")
|
||||
inbg.setConnectedNode(n6)
|
||||
inmx = n8.addInput("mix", "float")
|
||||
inmx.setConnectedNode(img3)
|
||||
|
||||
t1 = ng3.addNode("texcoord", "t1", "vector2")
|
||||
|
||||
m1 = ng3.addNode("multiply", "m1", "vector2")
|
||||
inp1 = m1.addInput("in1", "vector2")
|
||||
inp1.setConnectedNode(t1)
|
||||
m1.setInputValue("in2", 0.003)
|
||||
# If limited floating-point precision results in output value strings like "0.00299999",
|
||||
# you could instead write this as a ValueString (must add the input to the node first):
|
||||
# inp2 = m1.addInput("in2", "float")
|
||||
# inp2.setValueString("0.003")
|
||||
|
||||
n9 = ng3.addNode("noise2d", "n9", "color3")
|
||||
intx = n9.addInput("texcoord", "vector2")
|
||||
intx.setConnectedNode(m1)
|
||||
n9.setInputValue("amplitude", mx.Vector3(0.05,0.04,0.06))
|
||||
|
||||
n10 = ng3.addNode("inside", "n10", "color3")
|
||||
inmask = n10.addInput("mask", "float")
|
||||
inmask.setConnectedNode(img4)
|
||||
inp = n10.addInput("in", "color3")
|
||||
inp.setConnectedNode(n9)
|
||||
|
||||
n11 = ng3.addNode("add", "n11", "color3")
|
||||
inp1 = n11.addInput("in1", "color3")
|
||||
inp1.setConnectedNode(n10)
|
||||
inp2 = n11.addInput("in2", "color3")
|
||||
inp2.setConnectedNode(n8)
|
||||
|
||||
nout1 = ng3.addOutput("albedo", "color3")
|
||||
nout1.setConnectedNode(n11)
|
||||
nout2 = ng3.addOutput("areamask", "float")
|
||||
nout2.setConnectedNode(img3)
|
||||
|
||||
# It is not necessary to validate a document before writing but it's nice
|
||||
# to know for sure. And you can validate any element (and its children)
|
||||
# independently, not just the whole document.
|
||||
rc = ng1.validate()
|
||||
if (len(rc) >= 1 and rc[0]):
|
||||
print("Nodegraph %s is valid." % ng1.getName())
|
||||
else:
|
||||
print("Nodegraph %s is NOT valid: %s" % (ng1.getName(), str(rc[1])))
|
||||
rc = ng3.validate()
|
||||
if (len(rc) >= 1 and rc[0]):
|
||||
print("Nodegraph %s is valid." % ng3.getName())
|
||||
else:
|
||||
print("Nodegraph %s is NOT valid: %s" % (ng3.getName(), str(rc[1])))
|
||||
|
||||
outfile = "myNodeGraphs.mtlx"
|
||||
mx.writeToXmlFile(doc, outfile)
|
||||
print("Wrote nodegraphs to %s" % outfile)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user