Skip to content

Commit

Permalink
- Default nputs options (#4)
Browse files Browse the repository at this point in the history
- Physical Materials examples.
- Command line access.
  • Loading branch information
kwokcb committed Nov 23, 2023
1 parent 9fc7f77 commit f01f389
Show file tree
Hide file tree
Showing 29 changed files with 134 additions and 72 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
src/materialxgltf/__pycache__/
dist/
src/materialxgltf.egg-info/
build/
Binary file added docs/data/Lights/san_giuseppe_bridge.hdr
Binary file not shown.
Binary file modified docs/data/RTS/standard_surface_brass_tiled.mtlx.glb
Binary file not shown.
Binary file modified docs/data/RTS/standard_surface_brick_procedural.mtlx.glb
Binary file not shown.
Binary file modified docs/data/RTS/standard_surface_carpaint.mtlx.glb
Binary file not shown.
Binary file modified docs/data/RTS/standard_surface_chess_set.mtlx.glb
Binary file not shown.
Binary file modified docs/data/RTS/standard_surface_chrome.mtlx.glb
Binary file not shown.
Binary file modified docs/data/RTS/standard_surface_copper.mtlx.glb
Binary file not shown.
Binary file modified docs/data/RTS/standard_surface_default.mtlx.glb
Binary file not shown.
Binary file modified docs/data/RTS/standard_surface_glass.mtlx.glb
Binary file not shown.
Binary file modified docs/data/RTS/standard_surface_glass_tinted.mtlx.glb
Binary file not shown.
Binary file modified docs/data/RTS/standard_surface_gold.mtlx.glb
Binary file not shown.
Binary file modified docs/data/RTS/standard_surface_greysphere.mtlx.glb
Binary file not shown.
Binary file modified docs/data/RTS/standard_surface_greysphere_calibration.mtlx.glb
Binary file not shown.
Binary file modified docs/data/RTS/standard_surface_jade.mtlx.glb
Binary file not shown.
Binary file modified docs/data/RTS/standard_surface_look_brass_tiled.mtlx.glb
Binary file not shown.
Binary file modified docs/data/RTS/standard_surface_look_wood_tiled.mtlx.glb
Binary file not shown.
Binary file modified docs/data/RTS/standard_surface_marble_solid.mtlx.glb
Binary file not shown.
Binary file modified docs/data/RTS/standard_surface_metal_brushed.mtlx.glb
Binary file not shown.
Binary file modified docs/data/RTS/standard_surface_plastic.mtlx.glb
Binary file not shown.
Binary file modified docs/data/RTS/standard_surface_thin_film.mtlx.glb
Binary file not shown.
Binary file modified docs/data/RTS/standard_surface_velvet.mtlx.glb
Binary file not shown.
Binary file modified docs/data/RTS/standard_surface_wood_tiled.mtlx.glb
Binary file not shown.
64 changes: 32 additions & 32 deletions docs/gallery.html

Large diffs are not rendered by default.

22 changes: 11 additions & 11 deletions docs/gallery.md

Large diffs are not rendered by default.

34 changes: 34 additions & 0 deletions src/materialxgltf/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import sys, os
import subprocess

def main() -> int:
'''
Main entry point for running commands in the package.
'''
argCount = len(sys.argv)
if argCount < 2:
print('No arguments provided. Use -h or --help for help.')
return 1
if sys.argv[1] == '-h' or sys.argv[1] == '--help':
print('Usage: python -m materialxgltf <command> [options] where command is mtlx2gltf or gltf2mtlx')

# Check if the command is valid
cmdArgs = sys.argv[1:]
if cmdArgs[0] == 'mtlx2gltf':
cmdArgs[0] = 'mtlx2gltf.py'
elif cmdArgs[0] == 'gltf2mtlx':
cmdArgs[0] = 'gltf2mtlx.py'
else:
print('Unknown command specified:', cmdArgs[0])
return 1

# Build the command
cmd = ' '.join(cmdArgs)
packageLocation = os.path.dirname(__file__)
cmd = 'python ' + packageLocation + '/' + cmd

# Run the command
return subprocess.call(cmd, shell=True)

if __name__ == '__main__':
sys.exit(main())
79 changes: 51 additions & 28 deletions src/materialxgltf/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -872,7 +872,7 @@ def computeMeshMaterials(self, materialMeshList, materialCPVList, cnode, path, n
if 'name' in cnode:
cnodeName = cnode['name']
else:
cnodeName = self.GLTF_DEFAULT_NODE_PREFIX + str(nodeCount)
cnodeName = GLTF_DEFAULT_NODE_PREFIX + str(nodeCount)
nodeCount = nodeCount + 1
path = path + '/' + ( mx.createValidName(cnodeName) )

Expand Down Expand Up @@ -1068,6 +1068,7 @@ class MTLX2GLTFOptions(dict):
- 'geometryFile' : Path to geometry file to use for glTF. Default is ''.
- 'primsPerMaterial' : Create a new primitive per material in the MaterialX file and assign the material. Default is False.
- 'searchPath' : Search path for files. Default is empty.
- 'writeDefaultInputs' : Emit inputs even if they have default values. Default is False.
- 'debugOutput' : Print debug output. Default is True.
'''
def __init__(self, *args, **kwargs):
Expand All @@ -1085,6 +1086,7 @@ def __init__(self, *args, **kwargs):
self['debugOutput'] = True
self['createProceduralTextures'] = False
self['searchPath'] = mx.FileSearchPath()
self['writeDefaultInputs'] = False

class MTLX2GLTFWriter:
'''
Expand Down Expand Up @@ -1256,7 +1258,10 @@ def stringToScalar(self, value, type) -> None:
if len(splitvalue) > 1:
returnvalue = [float(x) for x in splitvalue]
else:
returnvalue = float(value)
if type == 'integer':
returnvalue = int(value)
else:
returnvalue = float(value)

return returnvalue

Expand Down Expand Up @@ -1362,44 +1367,46 @@ def graphToJson(self, graph, json, materials, textures, images, samplers):
if attrName not in skipAttr:
jsonNode[attrName] = node.getAttribute(attrName)

inputs = {}
inputs = []
for input in node.getInputs():

inputItem = {}
inputItem['name'] = input.getName()

if input.getValue() != None:
inputs[input.getName()] = {}
# If it's a file name then create a texture
inputType = input.getAttribute(mx.TypedElement.TYPE_ATTRIBUTE)
inputs[input.getName()]['type'] = inputType
inputItem['type'] = inputType
if inputType == mx.FILENAME_TYPE_STRING:
texture = {}
filename = input.getValueString()
self.initialize_gtlf_texture(texture, input.getNamePath(), filename, images)
textures.append(texture)
inputs[input.getName()]['texture'] = len(textures) -1
inputItem['texture'] = len(textures) -1
self.writeImageProperties(texture, samplers, node)
# Otherwise just set the value
else:
inputType = input.getAttribute(mx.TypedElement.TYPE_ATTRIBUTE)
value = input.getValueString()
value = self.stringToScalar(value, inputType)
inputs[input.getName()]['value'] = value
inputItem['value'] = value
else:
outputString = connection = input.getAttribute('output')
if len(connection) == 0:
connection = input.getAttribute('interfacename')
connection = input.getAttribute('interfacename')
if len(connection) == 0:
connection = input.getAttribute(MTLX_NODE_NAME_ATTRIBUTE)
connectionNode = graph.getChild(connection)
if connectionNode:
#inputs[input.getName()] = connectionNode.getNamePath()
inputs[input.getName()] = {}
inputType = input.getAttribute(mx.TypedElement.TYPE_ATTRIBUTE)
inputs[input.getName()]['type'] = inputType
inputItem['type'] = inputType
if debug:
inputs[input.getName()]['proceduralName'] = connectionNode.getNamePath()
inputs[input.getName()]['procedural'] = procDict[connectionNode.getNamePath()]
inputItem['proceduralName'] = connectionNode.getNamePath()
inputItem['procedural'] = procDict[connectionNode.getNamePath()]
outputString = input.getAttribute('output')
if len(outputString) > 0:
inputs[input.getName()]['output'] = outputString
inputItem['output'] = outputString

inputs.append(inputItem)

if len(inputs) > 0:
jsonNode['inputs'] = inputs

Expand Down Expand Up @@ -1821,8 +1828,9 @@ def writeFloatInput(self, pbrNode, inputName, gltfTextureName, gltfValueName, ma
value = pbrNode.getInputValue(inputName)
if value != None:
nodedef = pbrNode.getNodeDef()
# Don't write default values
if nodedef and nodedef.getInputValue(inputName) != value:
# Don't write default values, unless specified
writeDefaultInputs= self._options['writeDefaultInputs']
if nodedef and (writeDefaultInputs or nodedef.getInputValue(inputName) != value):
if remapper:
if value in remapper:
material[gltfValueName] = remapper[value]
Expand Down Expand Up @@ -1873,8 +1881,9 @@ def writeColor3Input(self, pbrNode, inputName, gltfTextureName, gltfValueName, m
if value:
nodedef = pbrNode.getNodeDef()
# Don't write default values
if nodedef and nodedef.getInputValue(inputName) != value:
material[gltfValueName] = [ value[0], value[1], value[2] ]
writeDefaultInputs= self._options['writeDefaultInputs']
if nodedef and (writeDefaultInputs or nodedef.getInputValue(inputName) != value):
material[gltfValueName] = [ value[0], value[1], value[2] ]


def writeCopyright(self, doc, gltfJson):
Expand Down Expand Up @@ -1902,18 +1911,22 @@ def materialX2glTF(self, doc, gltfJson, resetMaterials):
pbrNodes = {}
unlitNodes = {}

addInputsFromNodeDef = self._options['writeDefaultInputs']

for material in doc.getMaterialNodes():
shaderNodes = mx.getShaderNodes(material)
for shaderNode in shaderNodes:
category = shaderNode.getCategory()
path = shaderNode.getNamePath()
if category == MTLX_GLTF_PBR_CATEGORY and path not in pbrNodes:
#if addInputsFromNodeDef:
# shaderNode.addInputsFromNodeDef()
if addInputsFromNodeDef:
shaderNode.addInputsFromNodeDef()
shaderNode.removeChild('tangent')
shaderNode.removeChild('normal')
pbrNodes[path] = shaderNode
elif category == MTLX_UNLIT_CATEGORY_STRING and path not in unlitNodes:
#if addInputsFromNodeDef:
# shaderNode.addInputsFromNodeDef()
if addInputsFromNodeDef:
shaderNode.addInputsFromNodeDef()
unlitNodes[path] = shaderNode

materials_count = len(pbrNodes) + len(unlitNodes)
Expand Down Expand Up @@ -2063,9 +2076,9 @@ def materialX2glTF(self, doc, gltfJson, resetMaterials):
extensionName = 'KHR_procedurals'
if extensionName not in extensionsUsed:
extensionsUsed.append(extensionName)
if extensionName not in extensions:
extensions[extensionName] = {}
outputExtension = extensions[extensionName]
#if extensionName not in extensions:
# extensions[extensionName] = {}
#outputExtension = extensions[extensionName]

#jsonGraph = documentToJSON(imageGraph)
graphOutputs, procDict = self.graphToJson(imageGraph, gltfJson, materials, textures, images, samplers)
Expand All @@ -2076,7 +2089,17 @@ def materialX2glTF(self, doc, gltfJson, resetMaterials):
outputSpecifier = inputBaseColor.getAttribute('output')
if len(outputSpecifier) > 0:
connectionName = imageGraph.getNamePath() + '/' + outputSpecifier
outputExtension['baseColorTexture'] = procDict[connectionName]

# Add extension to texture entry
baseColorEntry = roughness['baseColorTexture'] = {}
baseColorEntry['index'] = 0 # Q: What should this be ?
if 'extensions' not in baseColorEntry:
baseColorEntry['extensions'] = {}
extensions = baseColorEntry['extensions']
if extensionName not in extensions:
extensions[extensionName] = {}
procExtensions = extensions[extensionName]
procExtensions['index'] = procDict[connectionName]

else:
if imageNode:
Expand Down
2 changes: 2 additions & 0 deletions src/materialxgltf/gltf2Mtlx.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def main():
parser.add_argument(dest='gltfFileName', help='Path containing glTF file to convert.')
parser.add_argument('--mtlxFileName', dest='mtlxFileName', default='', help='Name of MaterialX output file. If not specified the glTF name with "_tomtlx.mtlx" suffix will be used')
parser.add_argument('--createAssignments', dest='createAssignments', type=mx.stringToBoolean, default=True, help='Create material assignments. Default is True')
parser.add_argument('--addAllInputs', dest='addAllInputs', type=mx.stringToBoolean, default=False, help='Add all definition inputs to MaterialX shader nodes. Default is False')

opts = parser.parse_args()

Expand All @@ -57,6 +58,7 @@ def main():
# Perform conversion
options = GLTF2MtlxOptions()
options['createAssignments'] = opts.createAssignments
options['addAllInputs'] = opts.addAllInputs
converted, err = gltf2Mtlx(gltfFileName, mtlxFilePath, options)
print('Converted glTF file %s to MaterialX file: %s. Status: %s.' % (gltfFileName, mtlxFilePath, converted))
if not converted:
Expand Down
4 changes: 3 additions & 1 deletion src/materialxgltf/mtlx2gltf.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def mtlx2gltf(materialXFileName, gltfOutputFileName, options=MTLX2GLTFOptions())
f.close()
else:
return False, mtlx2glTFWriter.getLog()

if options['packageBinary']:
binaryFileName = str(gltfOutputFileName)
binaryFileName = binaryFileName.replace('.gltf', '.glb')
Expand All @@ -80,6 +80,7 @@ def main():
parser.add_argument('--translateShaders', dest='translateShaders', type=mx.stringToBoolean, default=False, help='Translate shaders to glTF. Default is False')
parser.add_argument('--bakeTextures', dest='bakeTextures', type=mx.stringToBoolean, default=False, help='Bake pattern graphs as textures. Default is False')
parser.add_argument('--bakeResolution', dest='bakeResolution', type=int, default=256, help='Bake image resolution. Default is 256')
parser.add_argument('--writeDefaultInputs', dest='writeDefaultInputs', type=mx.stringToBoolean, default=False, help='Write default inputs on shader nodes. Default is False')

opts = parser.parse_args()

Expand Down Expand Up @@ -124,6 +125,7 @@ def main():
options['translateShaders'] = opts.translateShaders
options['bakeTextures'] = opts.bakeTextures
options['bakeResolution'] = opts.bakeResolution
options['writeDefaultInputs'] = opts.writeDefaultInputs

# Set search path to default library path as well as folder containing MaterialX file
# and current path
Expand Down

0 comments on commit f01f389

Please sign in to comment.