This script asks for the location of a single image texture (can be diffuse/albedo, specular, or metallic) and will then proceed to automatically find and connect other image maps in the same directory to the appropriate connections on the universal material. (Will automatically invert gloss maps for roughness).
Requires that the image textures have the same naming prefix. Should work with most standard namings (e.g. you can call the albedo pass either albedo or diffuse and it'll pick it up), but you can include additional alternate namings just by adding them to the dictionary list ("listOfMaps") in the script--just don't override the very first item in the list: it's the official Octane texture name the script uses to connect the nodes.
The top button will automatically create the material and apply it to a selected object. Alternately, you can perform the steps manually using the buttons below it.
Only tested on Windows.
- Code: Select all
import maya.cmds as cmds
import maya.mel as mel
import pymel.core as pm
#import ntpath
from os import listdir
from os.path import isfile, join
imageFilePath = None
prefix = ''
pathText = None
prefixText = None
currentMaterial = None
def SetFilePath():
# Sets the file path to the images
basicFilter = "*.*"
global imageFilePath
global prefix
global prefixText
global pathText
fileNames = None
#fileNames = pm.fileDialog2(fileFilter=basicFilter, dialogStyle=1)
fileNames = cmds.fileDialog2(fileFilter=basicFilter, dialogStyle=2, caption='Locate albedo, specular, or metallic file',
fileMode=1, returnFilter=False)
if (fileNames == None): return False
if (len(fileNames)==0): return False
fileName = fileNames[0]
imageFilePath = os.path.dirname(fileName)
prefix = os.path.basename(fileName)
lowercasePrefix = prefix.lower()
if "diffuse" in lowercasePrefix:
indexOfDiffuseKeyword = lowercasePrefix.find('diffuse')
elif "diff" in lowercasePrefix:
indexOfDiffuseKeyword = lowercasePrefix.find('diff')
elif "albedo" in lowercasePrefix:
indexOfDiffuseKeyword = lowercasePrefix.find('albedo')
elif "specular" in lowercasePrefix:
indexOfDiffuseKeyword = lowercasePrefix.find('specular')
elif "spec" in lowercasePrefix:
indexOfDiffuseKeyword = lowercasePrefix.find('spec')
elif "metalness" in lowercasePrefix:
indexOfDiffuseKeyword = lowercasePrefix.find('metalness')
elif "metallic" in lowercasePrefix:
indexOfDiffuseKeyword = lowercasePrefix.find('metallic')
elif "metal" in lowercasePrefix:
indexOfDiffuseKeyword = lowercasePrefix.find('metal')
prefix = prefix[:indexOfDiffuseKeyword]
cmds.text(prefixText, edit=True, label=prefix)
cmds.text(pathText, edit=True, label=imageFilePath)
return True
def SetPrefix():
global prefix
result = pm.promptDialog(
title='Enter image texture prefix',
message='Enter prefix:',
tx=prefix,
button=['OK', 'Cancel'],
defaultButton='OK',
cancelButton='Cancel',
dismissString='Cancel')
if result == 'OK':
prefix = pm.promptDialog(query=True, text=True)
cmds.text(prefixText, edit=True, label=prefix)
def CreateMat():
global currentMaterial
global prefix
global imageFilePath
initialSelection = cmds.ls( sl=True)
transmissionMap = None
diffuseMap = None
metallicMap = None
specularMap = None
roughnessMap = None
anisotropyMap = None
rotationMap = None
dielectricMap = None
coatingMap = None
coatingRoughnessMap = None
sheenMap = None
sheenRoughnessMap = None
mediumMap = None
indexMap = None
bumpMap = None
normalMap = None
displacementMap = None
opacityMap = None
edgeRoundingMap = None
emissionMap = None
invertRoughness = False
filmWidthMap = None
listOfMaps = {"Transmission,transmission":transmissionMap,
"Albedo,diffuse,albedo":diffuseMap,
"Metallic,metal":metallicMap,
"Specular,specular":specularMap,
"Roughness,rough,gloss":roughnessMap,
"Rotation,rotation":rotationMap,
"DielectricIorMap,dielec,ior":dielectricMap,
"Coating, coat":coatingMap,
"CoatingRoughness, ctrough":coatingRoughnessMap,
"FilmWidth,film":filmWidthMap,
"Sheen,sheen":sheenMap,
"SheenRoughness,shnRough":sheenRoughnessMap,
"Medium,medium":mediumMap,
"Index,index,ior,refractiveindex,refractive_index":indexMap,
"Bump,bump":bumpMap,
"Normal,normal":normalMap,
"Displacement,displac":displacementMap,
"Opacity,opacity":opacityMap,
"Emission,emiss,lumin":emissionMap}
filesInDir = [f for f in listdir(imageFilePath) if isfile(join(imageFilePath, f))]
for currentFile in filesInDir:
if (prefix in currentFile):
currentFileLC = currentFile.lower()
for currentMap in listOfMaps:
#pm.confirmDialog( title='Current map: ', message=listOfMaps[currentMap], button=['OK'], dismissString='OK' )
searchTerms = currentMap.split(",")
for searchTerm in searchTerms:
#pm.confirmDialog( title='Current search term: ', message=searchTerm, button=['OK'], dismissString='OK' )
if (searchTerm in currentFileLC):
listOfMaps[currentMap] = imageFilePath + "/" + currentFile
if searchTerm == "gloss": # gloss maps are the inverse of roughness maps
#pm.confirmDialog( title='Found gloss1', message="Inverting", button=['OK'], dismissString='OK' )
invertRoughness = True
# Time to build the network
#commandText = 'shadingNode -asShader octaneGlossyMaterial -name "' + prefix + '_octUnivMat";'
#mel.eval(commandText)
materialName = prefix + '_octUnivMat'
SGName = prefix + '_SG'
currentMaterial = cmds.shadingNode('octaneUniversalMaterial', name=materialName, asShader=True)
shading_group= cmds.sets(name=SGName, renderable=True, noSurfaceShader=True, empty=True)
cmds.connectAttr('%s.outColor' % currentMaterial, '%s.surfaceShader' % shading_group)
for currentMap in listOfMaps:
if listOfMaps[currentMap] is not None:
keyWordTerms = currentMap.split(",")
userMessage = keyWordTerms[0] + " set to: " + listOfMaps[currentMap]
#pm.confirmDialog( title='Setting map', message=userMessage, button=['OK'], dismissString='OK' )
for currentMap in listOfMaps:
if listOfMaps[currentMap] is not None:
#pm.confirmDialog( title='Map present: ', message=listOfMaps[currentMap], button=['OK'], dismissString='OK' )
keyWordTerms = currentMap.split(",")
currentImageType = keyWordTerms[0]
nameOfImageNode = os.path.basename(listOfMaps[currentMap])
nameOfImageNode = os.path.splitext(nameOfImageNode)[0]
currentImageNode = cmds.shadingNode('octaneImageTexture', name=nameOfImageNode, asShader=True)
commandTex = 'connectAttr -f ' + currentImageNode + '.outTex ' + currentMaterial + '.' + currentImageType + ';'
mel.eval(commandTex)
commandTex = 'setAttr -type "string" ' + currentImageNode + '.File "' + listOfMaps[currentMap] + '";'
mel.eval(commandTex)
# Check for gloss map requiring invert
if ( (currentMap == "Roughness,rough,gloss") and (invertRoughness == True) ):
# Invert the roughness map
#pm.confirmDialog( title='Found gloss', message="Inverting", button=['OK'], dismissString='OK' )
commandTex = 'setAttr "' + currentImageNode + '.Invert" 1;'
mel.eval(commandTex)
cmds.select(initialSelection) # reselect the original objects
def getSGfromShader(shader=None):
if shader:
if cmds.objExists(shader):
sgq = cmds.listConnections(shader, d=True, et=True, t='shadingEngine')
if sgq:
return sgq[0]
return None
def assignObjectListToShader(objList=None, shader=None):
"""
Assign the shader to the object list
arguments:
objList: list of objects or faces
"""
# assign selection to the shader
shaderSG = getSGfromShader(shader)
if objList:
if shaderSG:
cmds.sets(objList, e=True, forceElement=shaderSG)
else:
print 'The provided shader didn\'t returned a shaderSG'
else:
print 'Please select one or more objects'
def assignSelectionToShader(shader=None):
sel = cmds.ls(sl=True, l=True)
if sel:
assignObjectListToShader(sel, shader)
def AssignMat():
assignSelectionToShader(currentMaterial)
def DoItAll():
#get initial selection
initialSelection = cmds.ls( sl=True)
dirFound = SetFilePath()
if dirFound:
CreateMat()
cmds.select(initialSelection) # reselect the original objects
AssignMat()
# Make a new window
#
window = pm.window( title="Octane Material Builder", iconName='Short Name', widthHeight=(500, 200) )
pm.columnLayout( adjustableColumn=True )
# Result: ui.ColumnLayout('window1|columnLayout98') #
prefixText = pm.text("Image prefix", align='left', font='boldLabelFont')
pathText = pm.text("Image path", align='left', font='boldLabelFont')
pm.button( label='LOCATE, CREATE, AND ASSIGN', command=lambda *args:DoItAll() )
pm.button( label='Locate diffuse texture', command=lambda *args:SetFilePath() )
pm.button( label='Set common image prefix (optional)', command=lambda *args:SetPrefix() )
pm.button( label='Create material', command=lambda *args:CreateMat() )
pm.button( label='Assign current mat to selected', command=lambda *args:AssignMat() )
# Result: ui.Button('window1|columnLayout98|button111') #
pm.button( label='Close', command=('pm.deleteUI(\"' + window + '\", window=True)') )
# Result: ui.Button('window1|columnLayout98|button112') #
pm.setParent( '..' )
# Result: u'' #
pm.showWindow( window )