Home Technical Talk

Assign shader to objects using pymel?

polycounter lvl 14
Offline / Send Message
mdeforge polycounter lvl 14
I've written a script in Maya using Pymel that generates a set of visual controls for a depth of field pass. It works (see image)! But the last thing on the wish list is for the surface shader that's required for the render to work be applied to all the objects in the scene.

depthscript.jpg

This is my first script, and oddly enough, out of the few challenges I had writing this, I just can't figure this part out. The documentation isn't helping. I'm probably using Pymel a bit wrong as well... I'm still reading up on some of the shortcuts I can take. For instance, I believe I can use >> to connect attributes. This works for now though.

The problem area is the last comment section down at the bottom. I've commented out some things I've tried. I keep getting back errors about the shader not existing, or the objects set not existing, depending on what it is I'm trying.
import pymel.core as pm

#Initialize
myCamera = pm.ls(sl = True)
planeScaleSize = 30
planeSubD = 8
myCamTransform = myCamera[0].translate.get()


#Create First Plane
myPlane = pm.polyPlane(n = 'NEAR_plane', w = planeScaleSize, h = planeScaleSize, sx = planeSubD, sy = planeSubD)
pm.parent('NEAR_plane', myCamera, relative = True)
pm.rotate('NEAR_plane', '-90deg', 0)
pm.move(0, 0, -5, ls = True, r = True, wd = True)
pm.setAttr('NEAR_planeShape.castsShadows', 0)
pm.setAttr('NEAR_planeShape.receiveShadows', 0)
pm.setAttr('NEAR_planeShape.motionBlur', 0)
pm.setAttr('NEAR_planeShape.primaryVisibility', 0)
pm.setAttr('NEAR_planeShape.smoothShading', 0)
pm.setAttr('NEAR_planeShape.visibleInReflections', 0)
pm.setAttr('NEAR_planeShape.visibleInRefractions', 0)

#Create Second Plane (Comes in parented)
pm.duplicate('NEAR_plane', n = 'FAR_plane')
pm.rotate('FAR_plane', '-90deg', 0)
pm.move(0, 0, -5, ls = True, r = True, wd = True)
pm.setAttr('FAR_planeShape.castsShadows', 0)
pm.setAttr('FAR_planeShape.receiveShadows', 0)
pm.setAttr('FAR_planeShape.motionBlur', 0)
pm.setAttr('FAR_planeShape.primaryVisibility', 0)
pm.setAttr('FAR_planeShape.smoothShading', 0)
pm.setAttr('FAR_planeShape.visibleInReflections', 0)
pm.setAttr('FAR_planeShape.visibleInRefractions', 0)


#Unparent //W means parented to the world
pm.parent('NEAR_plane', w = True)
pm.parent('FAR_plane', w = True)


#Create Distant Dimensions
pm.distanceDimension(sp = (myCamTransform.x, myCamTransform.y, myCamTransform.z), ep = (0, 0, -5))
pm.distanceDimension(sp = (myCamTransform.x, myCamTransform.y, myCamTransform.z), ep = (0, 0, -10))


#Rename
pm.rename('locator1', 'CAM_locator')
pm.rename('locator2', 'NEAR_locator')
pm.rename('locator3', 'FAR_locator')
pm.rename('distanceDimension1', 'NEAR_distanceDimension')
pm.rename('distanceDimension2', 'FAR_distanceDimension')


#Constrain and Group
pm.parentConstraint(myCamera, 'CAM_locator')
pm.parentConstraint('NEAR_plane', 'NEAR_locator')
pm.parentConstraint('FAR_plane', 'FAR_locator')
pm.group('NEAR_plane', 'FAR_plane', n = 'Planes')


#Parent and Maintain Offset
pm.parentConstraint(myCamera, 'Planes', mo = True)
pm.group('Planes', 'CAM_locator', 'NEAR_locator', 'FAR_locator', 'NEAR_distanceDimension', 'FAR_distanceDimension', n = 'ZDepth_Group')


#Select All
pm.select(all = True)
pm.createRenderLayer(g = True, n = 'ZDepth')


#Create Surface Shader
myShader = pm.shadingNode('surfaceShader', asShader = True, n = 'mySurfaceShader')
pm.sets(r= True, nss = True, em = True, n = 'mySurfaceShaderSG')
print myShader


#Create Multiple/Divide
pm.shadingNode('multiplyDivide', asUtility = True, n = 'myMultiDiv')
pm.setAttr('myMultiDiv.input2.input2X', -1)


#Create Sampler Info
pm.shadingNode('samplerInfo', asUtility = True, n = 'mySamplerInfo')


#Create setRange
pm.shadingNode('setRange', asUtility = True, n = 'myRangeNode')
pm.setAttr('myRangeNode.min.minX', 1)


#Hookup
pm.connectAttr('mySamplerInfo.pointCamera.pointCameraZ', 'myMultiDiv.input1.input1X')
pm.connectAttr('myMultiDiv.output.outputX', 'myRangeNode.value.valueX')
pm.connectAttr('myRangeNode.outValue.outValueX', 'mySurfaceShader.outColor.outColorR')
pm.connectAttr('myRangeNode.outValue.outValueX', 'mySurfaceShader.outColor.outColorG')
pm.connectAttr('myRangeNode.outValue.outValueX', 'mySurfaceShader.outColor.outColorB')
pm.connectAttr('NEAR_distanceDimensionShape.distance', 'myRangeNode.oldMin.oldMinX')
pm.connectAttr('FAR_distanceDimensionShape.distance', 'myRangeNode.oldMax.oldMaxX')


#Apply Shader to everything
#ssn = pm.select(ado = True)
ssn = pm.ls(sl = True) #<

pm.hyperShade(myShader, assign = True) #<
#pm.sets('mySurfaceShader', edit = True, forceElement = ssn)


Replies

  • haiddasalami
    Options
    Offline / Send Message
    haiddasalami polycounter lvl 14
    From what I see you need to do something like
    ssn = pm.ls(type = 'mesh')
    
    for i in ssn:
        assign shader
    

    Hopefully I understood your problem but just to clarify you want to assign the mesh to all meshes in the scene right? Does that include the near and far planes? If not then you can just filter them as I see you explicity named them. Your pm.ls(sl=true) wont work because it should select the myRangeNode as technically its the last thing created in maya which is "selected"
  • mdeforge
    Options
    Offline / Send Message
    mdeforge polycounter lvl 14
    Correct. I thought about excluding them, but it doesn't really matter. I changed the render stats so they aren't rendered anyway. Thanks for the tip about 'ls.' That little command seems to have a lot of tricks to it for doing something so seemingly simple.

    Using hyperShade is the way to go, right?

    Did this:
    #Apply Shader to everything ssn = pm.ls(type = 'mesh')
    for i in ssn:
    pm.hyperShade(myShader, assign = True)
    (The loop is indented, won't stick on forum)
    Got this:
    # Error: No shader is selected to be assigned # # Error: No renderable object is selected for assignment #
    # Error: No shader is selected to be assigned #
    # Error: No renderable object is selected for assignment #
    # Error: No shader is selected to be assigned #
    # Error: No renderable object is selected for assignment #
    I'm guessing it repeats it three times because I have three objects in the scene. At least ls seems to be picking the meshes up, but this damn shader...

    Bonus question: Looks like this material application will take place on the master layer. That's bad, as it will replace the textures. How can I switch to the render layer I created?
  • haiddasalami
    Options
    Offline / Send Message
    haiddasalami polycounter lvl 14
    you need to select the mesh first then assign. Thats my bad so:

    pm.select(i)

    then use hypershade to assign. Don't have maya on this laptop so cant test :(
  • mdeforge
    Options
    Offline / Send Message
    mdeforge polycounter lvl 14
    Lol, no worries. That got rid of the 'No renderable object is selected' error, but it's still saying 'No shader is selected to be assigned.'

    Is, "myShader = pm.shadingNode('surfaceShader', asShader = True, n = 'mySurfaceShader')" not enough to create a variable containing my shader? Did I not create my shader correctly? I even tried plugging the name into the hypergraph function directly. So, instead of: pm.hyperShade(myShader, assign = True) I did pm.hyperShade('mySurfaceShader', assign = True).

    Thanks for the help so far :)

    EDIT: I think the problem is I don't have a SG for my surfaceShader... looking into that now.
  • mdeforge
    Options
    Offline / Send Message
    mdeforge polycounter lvl 14
    Got it working.
    #Apply Shader to everything ssn = pm.ls(type = 'mesh')
    for i in ssn:
    pm.select(i)
    pm.hyperShade(assign = 'mySurfaceShader')

    Thanks haiddasalami!
  • haiddasalami
    Options
    Offline / Send Message
    haiddasalami polycounter lvl 14
    Ah glad to see you got it working!
Sign In or Register to comment.