+1 tag for Google+

Saturday, 22 November 2014

Adding ObjectID Pass to Render Output in Maya Part 2: The Script

In my previous post, Autodesk's article showed us how to create an ObjectId pass in our scene.

In the last post I also posted a snippet of PyMel script that creates a unique Id number for each object so each one will turn up a uniquely different colour from its neighbour in the objectId pass.

However the process still needed us to manually create a Mental Ray Output Pass in the camera's Mental Ray section.

Since then I have gone on to write a PyMel script to automate the process. So here is the script.

# -- code start --
from pymel.core import *
def uniqObjIdAssign():
    # Written by Patrick Woo
    # usage:   
    # - make sure mental ray is loaded, and set as your current renderer
    # - select the camera
    # - then select all the objects to give unique objectIDs to, and run this script
    # for more info go to:
    # http://patrickvfx.blogspot.com/2014/11/adding-objectid-pass-to-render-output.html
    if ls(sl=True)[0].getShape().nodeType()=='camera':
        camShape = ls(sl=True)[0].getShape()
    else:
        print 'first object selected must be a camera. script aborted.'
        return
    if ls('*miOutputPass_ObjId', type='mentalrayOutputPass'):
        # user has run this before
        select(ls('*miOutputPass_ObjId', type='mentalrayOutputPass'), replace=True)
        print 'an existing mentalrayOutputPass already exists. delete it, or rename it, then run the script again'
        return
    sel = ls(sl=True)[1:]
    opPassNode = createNode("mentalrayOutputPass", name='miOutputPass_ObjId')
    opPassNode.dataType.set(11) # set frame buffer type to "label(integer)1x32bit"
    opPassNode.fileMode.set(1) # sets the outputPass node to output to a file upon rendering
    opPassNode.fileName.set("_objId")
    connectTriesCounter = 0
    connectedFlag = False
    while not connectedFlag:
        try:
            connectAttr(opPassNode.message, camShape.miOutputShaderList[connectTriesCounter], f=False)
            connectedFlag = True        
        except:
            connectTriesCounter += 1
        if connectTriesCounter > 20:
            print 'too many tries to connect %s to %s, aborting.'%(opPassNode.name(), camShape.name())
            print "check the connections on %s's mental ray -> output shaders before running again"%camShape.name()
            return
    
    counter = 1 # 0 is black in colour 
    for x in sel:
        if x.getShape():
            # makes sure that the transform node isn't just an empty group 
            if "miLabel" not in str(x.listAttr()):
                addAttr (x, ln='miLabel', at='long', k=True);
            x.miLabel.set(counter) 
            print '%s.miLabel set to %i'%(x,x.miLabel.get())
            counter += 1
    return
uniqObjIdAssign()
# -- code end --

These are the steps you need to do before running the script.
- set your renderer to Mental Ray (the Mental Ray plug-in must be loaded)
- select first your camera
- then select the rest of your objects in the scene you wish to assign objectIds

The script does the following:
- get your camera's shape node
- create a mentalrayOutputPass node
- set the mentalrayOutputPass node's frame buffer type to "Label(Integer)1x32bit"
- set the mentalrayOutputPass node to output to a separate file when rendering
- set a suffix "_objId" for the output file  (so it does not clash with the file name of your main render)
- connect it to an empty entry in your camera shape's list of output shaders
- then go through the rest of the non-camera selection, and
  -  add the "miLabel" attribute if it does not exist
  - gives a unique integer to the object's "miLabel" attribute

On top of all these the script does some checks:
- to make sure the first selection is a camera
- to make sure the mentalrayOutputPass node with a name "miOutputPass_ObjId" does not already exist in the scene (I do not want the user to end up with a heap of mentalrayOutputPass nodes when he/she runs the script multiple times)

Additional tips and controls for the script:
The order of your selection matters.

If you do not  like the colours given to some of the objects, you can deselect those objects and re-add them to your existing selection in a different selection order, then run the script again. (Just make sure the first selected object is your camera).

If you want to re-run the script, make sure to delete the mentalrayOutputPass node connected to the camera, and you will be able to run the script again. 

If you'd like to keep an existing mentalrayOutputPass node, you can rename it with a "01" at the back, and the script will now run by adding yet another mentalrayOutputPass node, which you can then manually delete when the new node gets created. Ideally you should only have only one mentalrayOutputPass node attached to your camera, since all other mentalrayOutputPass nodes will command mental ray to re-render the same objectId passes and save the exact images back to the exact filenames, resulting in wasted rendering time.

I hope you find this useful. 

Drop me a note if it has helped you, or if you have ideas on how to improve it. :)