- Ziv

# OSL MOOM SHADER

The last project is to use MOOM(many objects, one material) shader in the scene. This shader allows artists to use one material on many objects but randomly assign textures that have been picked up.

To demo this function, I chose to create these small pills with emojis on it.

Step 1

Preparing the codes.

There are two codes that will be using.

"add_arnold_attrs"

This python code will create attributes with selected geometry. The attributes will then read the sourceimage folder for randomly using textures.

import maya.cmds as cmds

from random import uniform, choice

def add_string(attrname, paths):

attrname = 'mtoa_constant_' + attrname

shapes = []

selections = cmds.ls(sl=True)

for sel in selections:

shapes = cmds.listRelatives(sel, shapes=True)

# sel in a group

if shapes == None:

transforms = cmds.listRelatives(sel, children=True)

shapes = []

for tran in transforms:

shapes.extend(cmds.listRelatives(tran,shapes=True))

if len(shapes) == 0 or len(shapes[0]) == 0:

print('Cannot find a shape to add attribute')

continue

for shape in shapes:

if cmds.attributeQuery(attrname, node= shape, exists=True) == False:

cmds.addAttr(shape, ln=attrname, sn=attrname, nn=attrname, dt="string")

path= choice(paths)

cmds.setAttr(shape + '.' + attrname, path, type ="string")

#=======================================================================================

def add_rand_float(attrname, min_max_value, min_max=[0,10.0]):

attrname = 'mtoa_constant_' + attrname

#selections will be either a number of shapes (possibly only one shape),

#or one or more groups that contain shapes.

selections = cmds.ls(sl=True)

for sel in selections:

shapes = cmds.listRelatives(sel, shapes=True)

# sel in a group

if shapes == None:

transforms = cmds.listRelatives(sel, children=True)

shapes = []

for tran in transforms:

shapes.extend(cmds.listRelatives(tran,shapes=True))

if len(shapes) == 0 or len(shapes[0]) == 0:

print('Cannot find a shape to add attribute')

return

for shape in shapes:

if cmds.attributeQuery(attrname, node=shape, exists=True) == False:

cmds.addAttr(shape, ln=attrname, sn=attrname, nn= attrname,

k=True, at='double',

min=min_max[0], max=min_max[1], dv=0)

value = uniform(min_max_value[0], min_max_value[1])

cmds.setAttr(shape + '.' + attrname, value)

#=======================================================================================

def add_rand_int(attrname, min_max_value, min_max=[0,10.0]):

attrname = 'mtoa_constant_'+attrname

shapes = []

selections = cmds.ls(sl=True)

for sel in selections:

shapes = cmds.listRelatives(sel, s=True)

# sel is a shape, therefore, does not have shape relatives

if shapes == None:

transforms = cmds.listRelatives(sel, children=True)

shapes = []

for tran in transforms:

shapes.extend(cmds.listRelatives(tran, shapes=True))

if len(shapes) == 0 or len(shapes[0]) == 0:

print('Cannot find a shape to add attribute')

continue

for shape in shapes:

if cmds.attributeQuery(attrname, node=shape, exists=True) == False:

cmds.addAttr(shape, ln=attrname, sn=attrname, at='long',

min=min_max[0], max=min_max[1], dv=0)

value = uniform(min_max_value[0], min_max_value[1])

cmds.setAttr(shape + '.' + attrname, value)

#=======================================================================================

def add_rand_color(attrname, min_rgb, max_rgb):

attrname = 'mtoa_constant_'+ attrname

shapes = []

selections = cmds.ls(sl=True)

for sel in selections:

shapes = cmds.listRelatives(sel, s=True)

if shapes == None:

transforms = cmds.listRelatives(sel, children = True)

shapes = []

for tran in transforms:

shapes.extend(cmds.listRelatives(tran, shapes = True))

if len(shapes) == 0 or len (shapes[0]) ==0:

print ('Cannot find a shape to add attribute')

continue

for shape in shapes:

if cmds.attributeQuery(attrname, node=shape, exists=True) == False:

cmds.addAttr(shape, ln=attrname, sn=attrname, nn=attrname, at='float3',

usedAsColor=True, k=True)

red = attrname + "_r"

green = attrname + "_g"

blue = attrname + "_b"

cmds.addAttr(shape, ln = red, at ="float", k=True, parent=attrname)

cmds.addAttr(shape, ln = green, at ="float", k=True, parent=attrname)

cmds.addAttr(shape, ln = blue, at ="float", k=True, parent=attrname)

r = uniform(min_rgb[0], max_rgb[1])

g = uniform(min_rgb[0], max_rgb[1])

b = uniform(min_rgb[0], max_rgb[1])

cmds.setAttr(shape + '.' + attrname,r,g,b, type="float3")

"MoomTexture"

Create this OSL shader for Arnold to picks up textures.

shader

zlMoomTexture(

string mappath="",

color missingAttrColor = color(1,0,1),

int linearize = 0

[[

string widget = "boolean"

]],

float gamma = 2.2,

int flipV = 0 [[

string widget = "boolean"

]],

output color resultRGB = 0)

{

string pathvalue;

if(getattribute(mappath, pathvalue) == 1) {

resultRGB = texture(pathvalue, u, v);

if(linearize == 1) {

resultRGB[0] = pow(resultRGB[0], gamma);

resultRGB[1] = pow(resultRGB[1], gamma);

resultRGB[2] = pow(resultRGB[2], gamma);

}

if(flipV == 1) {

resultRGB = texture(pathvalue, u, 1-v);

}

else resultRGB = resultRGB;

}

else

resultRGB = missingAttrColor;

}

Step 2

I created one pill and manually duplicated and scattered them in the scene.

Step 3

With those pills selected, and execute the following python commend.

At the line 18, I also assigned a string call 'ziv' in order to specify the map path.

Step 4

Use the MoomTexture shader and link it to aiStandardSurface

With the Mappath assigned with 'ziv', it should read the sourceimage folder and textures properly.

Conclusion

This project is very useful and I'd like to keep this code into my usual creation workflow since it's very handy when there is bunch of objects need to assign with different textures.