Isotropix Forums

transfer material attributes from maya arnold to clarisse

Clarisse Scripting related topics

Re: transfer material attributes from maya arnold to clariss

Unread postby anabil » Thu Oct 26, 2017 3:29 am

janoshunyadi wrote:Nice to see our script pop up here. I think credit is due where it should belong ;)

https://forum.isotropix.com/viewtopic.php?f=5&t=3162&p=12934&hilit=clarisse_alshader_io#p12934

Btw. it's been on Github for a while for anyone to fork it:
https://github.com/kidintwo3/clarisse_alshader_io

Greets,
Janos


well i guess now we know the unknown hero who did the initial setup, i didn't find credits in the script itself to mention but i did in my post ;) and i hope you don't mind me adding to it.

cheers,
Ahmed
Last edited by anabil on Thu Oct 26, 2017 5:46 am, edited 1 time in total.
anabil
 
Posts: 22
Joined: Tue Mar 21, 2017 11:51 am

Re: transfer material attributes from maya arnold to clariss

Unread postby anabil » Thu Oct 26, 2017 5:42 am

**EDITED**

hi again,

after some tests i found out that the problem happens if i have a shader assigned to multiple geometries in maya so i modified the script to write the object_name as a list with all the geo's names instead of one string:

python code

import maya.cmds as cmds

import os
import json


def store_alstandard_mat_data(objA=None, file_path=None):

if objA == None:
objA = cmds.ls( sl=True )

"""
Store the Arnold AlStandard material attributes in a json file
Example: store_alstandard_mat_data(objA=['sphere1'], file_path='c:/test_mat.json')
:param shader_nameA: array, string name of the object to query from
:param file_path: str, full output path
:return:
"""

if not objA:
return

if not file_path:
return

disp = []
shader_nameA = []

for i in objA:
allChildren = cmds.listRelatives(i, ad=1)
for eachChild in allChildren:
# Get the shader groups attached to this particular object
shaderGroups = cmds.listConnections(cmds.listHistory(eachChild))
if shaderGroups is not None:
# Get the material attached to the shader group
materials = [x for x in cmds.ls(cmds.listConnections(shaderGroups), materials=1)]
#filtering only alSurface materials
if materials:
for mat in materials:
# If its AlSurface material add it to the list
if cmds.nodeType(mat) == 'alSurface':
if mat not in shader_nameA:
shader_nameA.append(mat)
# If its displacement material add it to the list
if cmds.nodeType(mat) == 'displacementShader':
if mat not in disp:
disp.append(mat)
if not shader_nameA:
return
# converting maya attribute names to clarisse names
clarisse_arnold_pairs = {'diffuse_front_color': 'diffuseColor',
'diffuse_front_strength': 'diffuseStrength',
'diffuse_roughness': 'diffuseRoughness',
'diffuse_back_color': 'backlightColor',
'diffuse_back_strength': 'backlightStrength',

'diffuse_sss_mix': 'sssMix',
'diffuse_sss_mode': 'sssMode',
'diffuse_sss_density_scale': 'sssDensityScale',
'diffuse_sss_color_1': 'sssRadiusColor',
'diffuse_sss_distance_1': 'sssRadius',
'diffuse_sss_weight_1': 'sssWeight1',
'diffuse_sss_color_2': 'sssRadiusColor2',
'diffuse_sss_distance_2': 'sssRadius2',
'diffuse_sss_weight_2': 'sssWeight2',
'diffuse_sss_color_3': 'sssRadiusColor3',
'diffuse_sss_distance_3': 'sssRadius3',
'diffuse_sss_weight_3': 'sssWeight3',
'diffuse_sss_group[0]': 'sssTraceSet',

'diffuse_normal_mode': None,
'diffuse_normal_input': 'diffuseNormal',

'specular_1_color': 'specular1Color',
'specular_1_strength': 'specular1Strength',
'specular_1_roughness': 'specular1Roughness',
'specular_1_anisotropy': 'specular1Anisotropy',
'specular_1_anisotropy_rotation': 'specular1Rotation',
'specular_1_fresnel_mode': 'specular1FresnelMode',
'specular_1_index_of_refraction': 'specular1Ior',
'specular_1_fresnel_preset': None,
'specular_1_fresnel_reflectivity': 'specular1Reflectivity',
'specular_1_fresnel_edge_tint': 'specular1EdgeTint',
'specular_1_brdf': 'specular1Distribution',
'specular_1_exit_color': None,
'specular_1_normal_mode': None,
'specular_1_normal_input': 'specular1Normal',

'specular_2_color': 'specular2Color',
'specular_2_strength': 'specular2Strength',
'specular_2_roughness': 'specular2Roughness',
'specular_2_anisotropy': 'specular2Anisotropy',
'specular_2_anisotropy_rotation': 'specular2Rotation',
'specular_2_fresnel_mode': 'specular1FresnelMode',
'specular_2_index_of_refraction': 'specular2Ior',
'specular_2_fresnel_preset': None,
'specular_2_fresnel_reflectivity': 'specular2Reflectivity',
'specular_2_fresnel_edge_tint': 'specular2EdgeTint',
'specular_2_brdf': 'specular1Distribution',
'specular_2_exit_color': None,
'specular_2_normal_mode': None,
'specular_2_normal_input': 'specular2Normal',

'transmission_color': 'transmissionColor',
'transmission_strength': 'transmissionStrength',
'transmission_link_to_specular': 'transmissionLinkToSpecular1',
'transmission_linked_to': None,
'transmission_index_of_refraction': 'transmissionIor',
'transmission_roughness': 'transmissionRoughness',
'transmittance_color': 'ssAttenuationColor',
'transmittance_density': 'ssDensityScale',
'transmission_exit_color': None,
'transmission_normal_mode': None,
'transmission_normal_input': 'transmissionNormal',

'emission_color': 'emissionColor',
'emission_strength': 'emissionStrength',

'normal_input' : 'normalCamera',

'opacity': 'opacity'}

shaderA = []

for shader_name in shader_nameA:

attributes = cmds.listAttr(shader_name, visible=True)
# getting the object name
shading_engine = cmds.listConnections(shader_name, type='shadingEngine')[0]
nameA = cmds.listRelatives(cmds.listConnections(shading_engine, type = 'mesh'))
object_name = []
for n in nameA:
if cmds.nodeType(n) == 'mesh':
if n not in object_name:
object_name.append(n)

#getting displacement shader
disp_conn_node = cmds.listConnections(shading_engine + '.displacementShader', d=False, s=True)

# base dictionary keys and values to be written in the json file
atrA = {'object_name' : object_name, 'disp_name' : [], 'name': shader_name, 'data': []}

#getting displacement texture path and adding it to the json dict
if disp_conn_node:
if cmds.nodeType(disp_conn_node) == 'displacementShader':
disp_file = cmds.listConnections(disp_conn_node[0] + '.displacement' , d=False, s=True)
if disp_file:
tx_disp_file_path = cmds.getAttr(disp_file[0] + '.fileTextureName')
# If it has a file path check if it's valid
if tx_disp_file_path:
if 'UDIM' in tx_disp_file_path:
disp_name = tx_disp_file_path.replace('\\', '/')
disp_attr = str(disp_name)
atrA['disp_name'].append(disp_attr)
else:
if os.path.exists(tx_disp_file_path):
disp_name = tx_disp_file_path.replace('\\', '/')
disp_attr = str(disp_name)
atrA['disp_name'].append(disp_attr)


for i in attributes:

value = cmds.getAttr(shader_name + '.' + str(i))

if value:
#check the attr is color attr not a texture
if isinstance(value, list):
value = value[0]

# Check if output plug has a file node connection
output_conn_node = cmds.listConnections(shader_name + '.' + str(i), d=False, s=True)

if output_conn_node:
if cmds.nodeType(output_conn_node, api=True) == 'kFileTexture':
tx_file_path = cmds.getAttr(output_conn_node[0] + '.fileTextureName')

# If it has a file path check if it's valid
if tx_file_path:
if 'UDIM' in tx_file_path:
value = tx_file_path.replace('\\', '/')
else:
if os.path.exists(tx_file_path):
value = tx_file_path.replace('\\', '/')

# Override for bump maps
# Check if input plug has a file node connection
bump_conn_node = cmds.listConnections(shader_name + '.' + str(i), d=False, s=True)

if bump_conn_node:
if cmds.nodeType(bump_conn_node) == 'bump2d':
bump_input = cmds.listConnections(bump_conn_node[0] + '.bumpValue', d=False, s=True)

if bump_input:
tx_bmp_file_path = cmds.getAttr(bump_input[0] + '.fileTextureName')

# If it has a file path check if it's valid
if tx_bmp_file_path:
if 'UDIM' in tx_bmp_file_path:
value = tx_bmp_file_path.replace('\\', '/')
else:
if os.path.exists(tx_bmp_file_path):
value = tx_bmp_file_path.replace('\\', '/')


for clar_id, arnold_id in clarisse_arnold_pairs.iteritems():
if i == arnold_id:
attr = {clar_id: value}
atrA['data'].append(attr)
break

if atrA:
shaderA.append(atrA)

#save data to the json file
if shaderA:
with open(file_path, 'w') as fp:
json.dump(shaderA, fp, sort_keys=False, indent=4)

print '[Info]Finished exporting material data...'

# Example script:
store_alstandard_mat_data(file_path='D:/Nabil/python_study/Clarisse/woman.json')


in clarisse, i used a for loop to search for objects and assign the shader to them, it works great but i still get this error :

Code: Select all
OfObjectFactory.get_object: Object 'project://scene/bunny_abc/R_eyeLid02_upShape' not found.
OfObjectFactory.find_attribute: Invalid attribute 'None.materials[0]'.
SetValues: The following attributes are invalid:
None.materials[0]
OfObjectFactory.get_object: Object 'project://scene/bunny_abc/R_eyeLid02_dnShape' not found.
OfObjectFactory.find_attribute: Invalid attribute 'None.materials[0]'.
SetValues: The following attributes are invalid:
None.materials[0]
OfObjectFactory.get_object: Object 'project://scene/bunny_abc/M_eye1_eyeball_smileShape' not found.
OfObjectFactory.find_attribute: Invalid attribute 'None.materials[0]'.
SetValues: The following attributes are invalid:
None.materials[0]
OfObjectFactory.get_object: Object 'project://scene/bunny_abc/R_eye1_eyeballShape2' not found.
OfObjectFactory.find_attribute: Invalid attribute 'None.materials[0]'.
SetValues: The following attributes are invalid:
None.materials[0]
OfObjectFactory.get_object: Object 'project://scene/bunny_abc/R_eye2_eyeballShape2' not found.
OfObjectFactory.find_attribute: Invalid attribute 'None.materials[0]'.
SetValues: The following attributes are invalid:
None.materials[0]
OfObjectFactory.get_object: Object 'project://scene/bunny_abc/R_eye2_eyeball_smileShape' not found.
OfObjectFactory.find_attribute: Invalid attribute 'None.materials[0]'.
SetValues: The following attributes are invalid:
None.materials[0]
OfObjectFactory.get_object: Object 'project://scene/bunny_abc/L_eye1_eyeball_smileShape' not found.
OfObjectFactory.find_attribute: Invalid attribute 'None.materials[0]'.
SetValues: The following attributes are invalid:
None.materials[0]
OfObjectFactory.get_object: Object 'project://scene/bunny_abc/L_eye2_eyeball_smileShape' not found.
OfObjectFactory.find_attribute: Invalid attribute 'None.materials[0]'.
SetValues: The following attributes are invalid:
None.materials[0]
OfObjectFactory.get_object: Object 'project://scene/bunny_abc/L_eye2_eyeball_winkShape' not found.
OfObjectFactory.find_attribute: Invalid attribute 'None.materials[0]'.
SetValues: The following attributes are invalid:
None.materials[0]
OfObjectFactory.get_object: Object 'project://scene/bunny_abc/R_eye1_eyeball_winkShape' not found.
OfObjectFactory.find_attribute: Invalid attribute 'None.materials[0]'.
SetValues: The following attributes are invalid:
None.materials[0]
OfObjectFactory.get_object: Object 'project://scene/bunny_abc/L_eye1_eyeball_winkShape' not found.
OfObjectFactory.find_attribute: Invalid attribute 'None.materials[0]'.
SetValues: The following attributes are invalid:
None.materials[0]
OfObjectFactory.get_object: Object 'project://scene/bunny_abc/M_eye1_eyeball1Shape' not found.
OfObjectFactory.find_attribute: Invalid attribute 'None.materials[0]'.
SetValues: The following attributes are invalid:
None.materials[0]
OfObjectFactory.get_object: Object 'project://scene/bunny_abc/R_eye1_eyeballShape' not found.
OfObjectFactory.find_attribute: Invalid attribute 'None.materials[0]'.
SetValues: The following attributes are invalid:
None.materials[0]
OfObjectFactory.get_object: Object 'project://scene/bunny_abc/R_eye1_eyeballShape3' not found.
OfObjectFactory.find_attribute: Invalid attribute 'None.materials[0]'.
SetValues: The following attributes are invalid:
None.materials[0]
OfObjectFactory.get_object: Object 'project://scene/bunny_abc/R_eye2_eyeballShape' not found.
OfObjectFactory.find_attribute: Invalid attribute 'None.materials[0]'.
SetValues: The following attributes are invalid:
None.materials[0]
OfObjectFactory.get_object: Object 'project://scene/bunny_abc/R_eye2_eyeball1Shape' not found.
OfObjectFactory.find_attribute: Invalid attribute 'None.materials[0]'.
SetValues: The following attributes are invalid:
None.materials[0]
OfObjectFactory.get_object: Object 'project://scene/bunny_abc/R_eye2_eyeballShape3' not found.
OfObjectFactory.find_attribute: Invalid attribute 'None.materials[0]'.
SetValues: The following attributes are invalid:


and this is the new edited clarisse script:

python code

import ix

import os
import json
import ntpath


def read_mat_data(file_path=None, default_path="project://scene"):

#putting the function to a history stack so you could CTR+Z
ix.begin_command_batch('CreateShadersAndAssign')

if not file_path:
return

if not os.path.exists(file_path):
return

# Open the json file and read the data
with open(file_path, 'r') as fp:
dataA = json.load(fp)

if not dataA:
return

for shader in dataA:
if shader:
shader_name = shader['name']
objectA = shader['object_name']
disp_texture = shader['disp_name']

if disp_texture:

disp_tex = shader.get('disp_name')[0]

# create a displacement node
disp_node = ix.cmds.CreateObject(str(ntpath.basename(disp_tex)) + "_disp",
"Displacement", "Global",
default_path)
# create texture for displacement
disp_TextureNode = ix.cmds.CreateObject(str(ntpath.basename(disp_tex)) + "_dispTX",
"TextureStreamedMapFile", "Global",
default_path)

# setting displacement texture values
ix.cmds.SetTexture([disp_node.get_full_name() + ".front_value"],
disp_TextureNode.get_full_name())

ix.cmds.SetValues([disp_TextureNode.get_full_name() + ".filename[0]"], [str(disp_tex)])
ix.cmds.SetValues([disp_TextureNode.get_full_name() + ".color_space_auto_detect"], ["0"])
ix.cmds.SetValues([disp_TextureNode.get_full_name() + ".file_color_space"], ["linear"])


if objectA:
object_name = shader.get('object_name')

# Create Physical Material
if shader_name:
standard_mat = ix.cmds.CreateObject(str(shader_name) + '_mat', "MaterialPhysicalStandard", "Global",
default_path)
if standard_mat:
attributes_data = shader.get('data')

if attributes_data:
for i in attributes_data:
if i:

if isinstance(i, dict):
for clar_id, val in i.iteritems():

# Everything that is a list considered as color values
if isinstance(val, list) and len(val) == 3:
ix.cmds.SetValues([standard_mat.get_full_name() + "." + str(clar_id)],
[str(val[0]), str(val[1]), str(val[2])])

# Everything that is a string is considered as a file path
elif isinstance(val, basestring):
texture_node = ix.cmds.CreateObject(str(ntpath.basename(val)) + "_tx",
"TextureStreamedMapFile", "Global",
default_path)

if texture_node:

ix.cmds.SetValues([texture_node.get_full_name() + ".filename[0]"],
[str(val)])


# for bump mapping
if clar_id == 'normal_input':
#print 'i am a normal input'
bump_node = ix.cmds.CreateObject(str(ntpath.basename(val)) + "_bumpNode",
"TextureBumpMap", "Global",
default_path)

ix.cmds.SetTexture([bump_node.get_full_name() + ".input"],
texture_node.get_full_name())

ix.cmds.SetTexture([standard_mat.get_full_name() + "." + str(clar_id)],
bump_node.get_full_name())
else:
#everything that's not a bump map
ix.cmds.SetTexture([standard_mat.get_full_name() + "." + str(clar_id)],
texture_node.get_full_name())
else:
# Set the attribute
ix.cmds.SetValues([standard_mat.get_full_name() + "." + str(clar_id)],
[str(val)])


########################################SHADER ASSIGNMENT########################################################

#filtering by name from the json file
for n in object_name:
#A container that will contain all the items in the scene
objects = ix.api.OfObjectVector()
filter = "%s" % str(n)
# This function will looking for matching object with le filter.
item = ix.application.get_factory().get_object('project://scene/woman_abc/%s' % str(filter) )
print item
# assign the newly created shader to that object
ix.cmds.SetValues( [str(item) + ".materials[0]"], [str(standard_mat)] )
# assign displacement to object if any
if disp_texture:
ix.cmds.SetValues( [str(item) + ".displacements[0]"], [str(disp_node)] )

########################################SHADER ASSIGNMENT########################################################

#putting the function to a history stack so you could CTR+Z
ix.end_command_batch()


# Example Script:
read_mat_data(file_path='D:/Nabil/python_study/Clarisse/woman.json', default_path="project://scene")


UPDATE: now everything works great, the script exports the UDIM textures data as well, and assigns everything correctly.

one problem here in the clarisse script,
to get the object by name i'm using hard coded path to my alembic directory like so:
Code: Select all
item = ix.application.get_factory().get_object('project://scene/woman_abc/%s' % str(filter) )

i want to make it more dynamic and search in the whole scene instead, can you please take a look and let me know how to fix this?

thank you,
Ahmed
anabil
 
Posts: 22
Joined: Tue Mar 21, 2017 11:51 am

Re: transfer material attributes from maya arnold to clariss

Unread postby bvaldes » Thu Oct 26, 2017 10:01 am

Hi,

When you import your abc by script, you can grab the filename. Then the directory will be the name of the abc without the extension:

python code

import os
# import ABC by type
files = ix.api.GuiWidget.open_files(ix.application, '', 'Import...', "Scene\t*.{abc}")
currentContext = ix.get_current_context()
for i in range(files.get_count()):
file = files[i]
ix.import_scene(file)
name = os.path.basename(file)
path = currentContext + "/" + name

# Grab all the abc item in the imported context
objects = ix.api.OfObjectVector()
filter = path + "/*"
className = "Geometry"
ix.application.get_matching_objects(objects, filter, classname)


I hope this help.

Regards
Benoit VALDES
Isotropix
Clarisse QA
User avatar
bvaldes
 
Posts: 160
Joined: Mon Sep 26, 2016 11:44 am

Re: transfer material attributes from maya arnold to clariss

Unread postby anabil » Mon Oct 30, 2017 9:33 am

Hi,

thank you bvaldes, it definitely helped.
i can call this one done now.

you can now use this script to export data from maya whether the shader was alsurface, aiStandard or maya shaders.(at least the main attributes,
like color, bump, transparency and displacement). alSurface is the best result of course, i just thought if i add other shaders as well(which is very easy now) it'll give us a head start in clarisse.

in maya, select the objects you want to write its data, specify where to write the json file and run..

python code

import maya.cmds as cmds

import os
import json

"""
PLEASE NOTE : THIS SCRIPT WILL NOT EXPORT DATA CORRECTLY IF YOU HAVE ANY COMPLICATED SHADER SETUP IN MAYA LIKE LAYERED
SHADERS/TESTURES
OR UTILITY NODES!!
IMPORTANT NOTE : MAKE SURE YOUR OBJECTS NAMES IN MAYA ARE UNIQUE or otherwise the script will fail!!
"""
#############################Attributes pairs between arnold and clarisse###################################

clarisse_aiStandard_pairs = {
'diffuse_front_color': 'color',
'diffuse_front_strength': 'Kd',
'diffuse_back_strength': 'Kb',

'specular_1_color': 'KsColor',
'specular_1_strength': 'Ks',
'specular_1_roughness': 'specularRoughness',
'specular_1_anisotropy': 'specularAnisotropy',
'specular_1_anisotropy_rotation': 'specularRotation',
'specular_1_fresnel_reflectivity': 'Ksn',

'transmission_color': 'KtColor',
'transmission_strength': 'Kt',
'transmission_index_of_refraction': 'IOR',
'transmission_roughness': 'refractionRoughness',
'transmittance_color': 'transmittance',
'emission_color': 'emissionColor',
'emission_strength': 'emission',

'normal_input' : 'normalCamera',
'opacity': 'opacity'
}
clarisse_Maya_pairs = {
'diffuse_front_color': 'color',
'specular_1_color': 'specularColor',
'normal_input' : 'normalCamera',
'opacity' : 'transparency'
}
clarisse_alSurface_pairs = {
'diffuse_front_color': 'diffuseColor',
'diffuse_front_strength': 'diffuseStrength',
'diffuse_roughness': 'diffuseRoughness',
'diffuse_back_color': 'backlightColor',
'diffuse_back_strength': 'backlightStrength',

'diffuse_sss_mix': 'sssMix',
'diffuse_sss_mode': 'sssMode',
'diffuse_sss_density_scale': 'sssDensityScale',
'diffuse_sss_color_1': 'sssRadiusColor',
'diffuse_sss_distance_1': 'sssRadius',
'diffuse_sss_weight_1': 'sssWeight1',
'diffuse_sss_color_2': 'sssRadiusColor2',
'diffuse_sss_distance_2': 'sssRadius2',
'diffuse_sss_weight_2': 'sssWeight2',
'diffuse_sss_color_3': 'sssRadiusColor3',
'diffuse_sss_distance_3': 'sssRadius3',
'diffuse_sss_weight_3': 'sssWeight3',
'diffuse_sss_group[0]': 'sssTraceSet',

'diffuse_normal_mode': None,
'diffuse_normal_input': 'diffuseNormal',

'specular_1_color': 'specular1Color',
'specular_1_strength': 'specular1Strength',
'specular_1_roughness': 'specular1Roughness',
'specular_1_anisotropy': 'specular1Anisotropy',
'specular_1_anisotropy_rotation': 'specular1Rotation',
'specular_1_fresnel_mode': 'specular1FresnelMode',
'specular_1_index_of_refraction': 'specular1Ior',
'specular_1_fresnel_preset': None,
'specular_1_fresnel_reflectivity': 'specular1Reflectivity',
'specular_1_fresnel_edge_tint': 'specular1EdgeTint',
'specular_1_brdf': 'specular1Distribution',
'specular_1_exit_color': None,
'specular_1_normal_mode': None,
'specular_1_normal_input': 'specular1Normal',#

'specular_2_color': 'specular2Color',
'specular_2_strength': 'specular2Strength',
'specular_2_roughness': 'specular2Roughness',
'specular_2_anisotropy': 'specular2Anisotropy',
'specular_2_anisotropy_rotation': 'specular2Rotation',
'specular_2_fresnel_mode': 'specular1FresnelMode',
'specular_2_index_of_refraction': 'specular2Ior',
'specular_2_fresnel_preset': None,
'specular_2_fresnel_reflectivity': 'specular2Reflectivity',
'specular_2_fresnel_edge_tint': 'specular2EdgeTint',
'specular_2_brdf': 'specular1Distribution',
'specular_2_exit_color': None,
'specular_2_normal_mode': None,
'specular_2_normal_input': 'specular2Normal',

'transmission_color': 'transmissionColor',
'transmission_strength': 'transmissionStrength',
'transmission_link_to_specular': 'transmissionLinkToSpecular1',
'transmission_linked_to': None,
'transmission_index_of_refraction': 'transmissionIor',
'transmission_roughness': 'transmissionRoughness',
'transmittance_color': 'ssAttenuationColor',
'transmittance_density': 'ssDensityScale',
'transmission_exit_color': None,
'transmission_normal_mode': None,
'transmission_normal_input': 'transmissionNormal',

'emission_color': 'emissionColor',
'emission_strength': 'emissionStrength',

'normal_input' : 'normalCamera',

'opacity': 'opacity'
}

clarisse_arnold_pairs = { 'aiStandard' : clarisse_aiStandard_pairs, 'alSurface' : clarisse_alSurface_pairs, 'blinn' : clarisse_Maya_pairs
, 'lambert' : clarisse_Maya_pairs, 'phong' : clarisse_Maya_pairs, 'phongE' : clarisse_Maya_pairs}

############################################################################################################

def store_alstandard_mat_data(objA=None, file_path=None):

if objA == None:
objA = cmds.ls( sl=True )
"""
***for perfect results use alSurface shaders in maya***
**you can export shader data from (mayaShaders, aiStandard, alSurface), if you want more shaders you can add pairs to
"clarisse_arnold_pairs" dictionary in the begining of the script and it will export automatically the new added shader Types!!
***Store the Arnold AlStandard material attributes in a json file

Example: store_alstandard_mat_data(objA=['sphere1'], file_path='c:/test_mat.json')
:param shader_nameA: array, string name of the object to query from
:param file_path: str, full output path
"""
if not objA:
print 'please select objects to begin exporting data'
return

if not file_path:
print 'please specify a path to save the JSON file'
return

shader_nameA_dict = {}

for i in objA:
allChildren = cmds.listRelatives(i, ad=1)
for eachChild in allChildren:
# Get the shader groups attached to this particular object
shaderGroups = cmds.listConnections(cmds.listHistory(eachChild))
if shaderGroups is not None:
# Get the material attached to the shader group
materials = [x for x in cmds.ls(cmds.listConnections(shaderGroups), materials=1)]
#filtering materials and adding it the material dict
if materials:
for mat in materials:
nodeType = cmds.nodeType(mat)
if not nodeType in shader_nameA_dict.keys():
shader_nameA_dict[nodeType] = []
if not mat in shader_nameA_dict.values():
shader_nameA_dict[nodeType].append(mat)

if not shader_nameA_dict:
return

shaderA = []

for node_type, shader_nameA in shader_nameA_dict.iteritems():
if node_type:
for shader_name in shader_nameA:
shaderName = shader_name
#checking for namespaces
if ':' in shaderName:
shaderName = shader_name.split(':')[-1]

attributes = cmds.listAttr(shader_name, visible=True)

#adding normal attr to the list if it's aiStandard
if node_type == 'aiStandard':
attributes.append('normalCamera')

# getting the object name
shading_engine = cmds.listConnections(shader_name, type='shadingEngine')[0]
nameA = cmds.listRelatives(cmds.listConnections(shading_engine, type = 'mesh'))
object_name = []

# adding the object name to the list without namespaces
for n in nameA:
if cmds.nodeType(n) == 'mesh':
if ':' in n:
n = n.split(':')[-1]
if n not in object_name:
object_name.append(n)

#getting displacement shader
disp_conn_node = cmds.listConnections(shading_engine + '.displacementShader', d=False, s=True)

# base dictionary keys and values to be written in the json file
atrA = {'object_name' : object_name, 'disp_name' : [], 'name': shaderName, 'data': [], 'normal_type': []}

#getting displacement texture path and adding it to the json dict
if disp_conn_node:
if cmds.nodeType(disp_conn_node) == 'displacementShader':
disp_file = cmds.listConnections(disp_conn_node[0] + '.displacement' , d=False, s=True)
if disp_file:
tx_disp_file_path = cmds.getAttr(disp_file[0] + '.fileTextureName')
# If it has a file path check if it's valid
if tx_disp_file_path:
if os.path.exists(tx_disp_file_path) or 'UDIM' in tx_disp_file_path:
disp_name = tx_disp_file_path.replace('\\', '/')
disp_attr = str(disp_name)
atrA['disp_name'].append(disp_attr)


for i in attributes:

value = cmds.getAttr(shader_name + '.' + str(i))

if value != None:
#check if the attr is color value not a texture
if isinstance(value, list):
#inverting transparency for maya shaders
if i == 'transparency':
value = [1-t for t in value[0]]
else:
value = value[0]

# Check if output plug has a file node connection
output_conn_node = cmds.listConnections(shader_name + '.' + str(i), d=False, s=True)

if output_conn_node:
if cmds.nodeType(output_conn_node, api=True) == 'kFileTexture':
tx_file_path = cmds.getAttr(output_conn_node[0] + '.fileTextureName')

# If it has a file path check if it's valid
if tx_file_path:
if os.path.exists(tx_file_path) or 'UDIM' in tx_file_path:
value = tx_file_path.replace('\\', '/')

# Override for bump maps
# Check if input plug has a file node connection
bump_conn_node = cmds.listConnections(shader_name + '.' + str(i), d=False, s=True)
if bump_conn_node:
if cmds.nodeType(bump_conn_node) == 'bump2d':
#checking whether it's a bump or normal
normalType = cmds.getAttr(bump_conn_node[0] + '.bumpInterp')
if normalType == 0:
atrA['normal_type'].append('TextureBumpMap')
if normalType == 1:
atrA['normal_type'].append('TextureNormalMap')

bump_input = cmds.listConnections(bump_conn_node[0] + '.bumpValue', d=False, s=True)

if bump_input:
tx_bmp_file_path = cmds.getAttr(bump_input[0] + '.fileTextureName')

# If it has a file path check if it's valid
if tx_bmp_file_path:
if os.path.exists(tx_bmp_file_path) or 'UDIM' in tx_bmp_file_path:
value = tx_bmp_file_path.replace('\\', '/')
#getting the corresponding dict based on the node_type
pairs = clarisse_arnold_pairs.get(node_type)
if pairs:
for clar_id, arnold_id in pairs.iteritems():
if i == arnold_id:
attr = {clar_id: value}
atrA['data'].append(attr)

if atrA:
if not atrA in shaderA:
shaderA.append(atrA)

#testing the values
# for v in shaderA:
# for k, v in v.iteritems():
# print k,v


#save data to the json file
if shaderA:
with open(file_path, 'w') as fp:
json.dump(shaderA, fp, sort_keys=False, indent=4)

print '[Info]Finished exporting material data...'

# Example script:
store_alstandard_mat_data(file_path='D:/your_path/Clarisse/tank.json')


in clarisse, select the context containing the geometries, specify where is the json file and run..


python code

import ix

import os
import json
import ntpath


def read_mat_data(file_path=None, current_context = None, default_path="project://scene"):

"""
file_path: path to the json file on your computer

current_context: the context where your imported geometry are in and the context the new shaders from the json file will be assigned to
, you can also type the path to the context like so:
----> current_context = "project://scene/my_model_context"

default_path: path to where you want to create your textures and materials, default is: "project://scene"

"""

#putting the function to a history stack so you could CTR+Z
ix.begin_command_batch('CreateShadersAndAssign')

if current_context == None:
current_context = ix.get_current_context()

if not current_context:
return

if not file_path:
return

if not os.path.exists(file_path):
return

# Open the json file and read the data
with open(file_path, 'r') as fp:
dataA = json.load(fp)

if not dataA:
return

tex_context = ix.cmds.CreateContext("textures", default_path )
mat_context = ix.cmds.CreateContext("materials", default_path )

allObjects = []
all_materials = []

for shader in dataA:
if shader:
shader_name = shader['name']
objectA = shader['object_name']
disp_texture = shader['disp_name']

if disp_texture:

disp_tex = shader.get('disp_name')[0]

# create a displacement node
disp_node = ix.cmds.CreateObject(str(ntpath.basename(disp_tex)) + "_disp",
"Displacement", "Global",
tex_context)
# create texture for displacement
disp_TextureNode = ix.cmds.CreateObject(str(ntpath.basename(disp_tex)) + "_dispTX",
"TextureStreamedMapFile", "Global",
tex_context)

# setting displacement texture values
ix.cmds.SetTexture([disp_node.get_full_name() + ".front_value"],
disp_TextureNode.get_full_name())

ix.cmds.SetValues([disp_TextureNode.get_full_name() + ".filename[0]"], [str(disp_tex)])
ix.cmds.SetValues([disp_TextureNode.get_full_name() + ".color_space_auto_detect"], ["0"])
ix.cmds.SetValues([disp_TextureNode.get_full_name() + ".file_color_space"], ["linear"])


if objectA:
object_name = shader.get('object_name')

# Create Physical Material
if shader_name:
standard_mat = ix.cmds.CreateObject(str(shader_name) + '_mat', "MaterialPhysicalStandard", "Global",
mat_context)
#setting spec value to 0 by default
ix.cmds.SetValues([standard_mat.get_full_name() + ".specular_1_strength" ],
["0"])

#storing all shaders in one fat list just in case
all_materials.append(standard_mat)

#setting defferent attrs
if standard_mat:
attributes_data = shader.get('data')

if attributes_data:
for i in attributes_data:
if i:

if isinstance(i, dict):
for clar_id, val in i.iteritems():
if val !=None:

# Everything that is a list considered as color values
if isinstance(val, list) and len(val) == 3:
ix.cmds.SetValues([standard_mat.get_full_name() + "." + str(clar_id)],
[str(val[0]), str(val[1]), str(val[2])])

# Everything that is a string is considered as a file path
elif isinstance(val, basestring):
tex_name = ntpath.basename(val)
if tex_name:
texture_node = ix.cmds.CreateObject(str(tex_name) + "_tx",
"TextureStreamedMapFile", "Global", tex_context )

if texture_node:

ix.cmds.SetValues([texture_node.get_full_name() + ".filename[0]"],
[str(val)])


# for bump mapping
if clar_id == 'normal_input':
bumpType = shader.get('normal_type')[0]
#print 'i am a normal input'
bump_node = ix.cmds.CreateObject(str(ntpath.basename(val)) + "_bumpNode",
str(bumpType), "Global",
tex_context)

ix.cmds.SetTexture([bump_node.get_full_name() + ".input"],
texture_node.get_full_name())

ix.cmds.SetTexture([standard_mat.get_full_name() + "." + str(clar_id)],
bump_node.get_full_name())
else:
#everything that's not a bump map
ix.cmds.SetTexture([standard_mat.get_full_name() + "." + str(clar_id)],
texture_node.get_full_name())
else:
# Set the attribute
ix.cmds.SetValues([standard_mat.get_full_name() + "." + str(clar_id)],
[str(val)])


########################################SHADER ASSIGNMENT########################################################

#filtering by name from the json file
allObjects = []
for n in object_name:
if n:
#A container that will contain all the items in the scene
objects = ix.api.OfObjectVector()
filter = "%s" % str(n)
filterz = "*%s" % str(n)
className = "Geometry"
# This function will looking for matching object with le filter.
item = ix.application.get_factory().get_object('%s/%s' % ( str(current_context), str(filter) ) )

####YOU CAN ENABLE THE BELOW THREE LINES IF YOU WANT TO GET THE ITEM NAME FROM THE WHOLE SCENE###########################

#if not item:
#ix.application.get_matching_objects(objects, filterz, className)
#item = objects[0]

#######################################################################################################################

# assign the newly created shader to that object if found

if item:
allObjects.append(item)
ix.cmds.SetValues( [str(item) + ".materials[0]"], [str(standard_mat)] )
# assign displacement to object if any
if disp_texture:
ix.cmds.SetValues( [str(item) + ".displacements[0]"], [str(disp_node)] )
shading_name = str(current_context).split('/')[-1]
shadingLayer = ix.cmds.CreateShadingLayerForItems(allObjects, 2, mat_context)
ix.cmds.RenameItem(str(shadingLayer), '%s___shading_layer' % shading_name )
#print len(all_materials)

# print '\n %s ' % len(allObjects)

########################################SHADER ASSIGNMENT########################################################

#putting the function to a history stack so you could CTR+Z
ix.end_command_batch()


# Example Script:
read_mat_data(file_path='D:/your_path/Clarisse/tank.json', default_path="project://scene")


this script will automatically create, set attributes and assign alsuface materials, bump or normal nodes(depending on what you were using in maya)and displacement shaders.

Cheers,
Ahmed
anabil
 
Posts: 22
Joined: Tue Mar 21, 2017 11:51 am

Previous

Return to Scripting