Jun 242015
 

A quick script here to convert Gizmos in Nuke into Groups. Gizmos are nice in theory in that they provide reusable groups of nodes for users to interact with, but they’re often more trouble than they’re worth, especially if you need to send your Nuke scripts to someone else. Here’s a script that just converts all the Gizmos in your scene into groups seamlessly:

import nuke

def isGizmo(node):
    return 'gizmo_file' in node.knobs()
    
def getGizmos():
    allNodes = nuke.allNodes()
    if allNodes:
        gizmos = [f for f in allNodes if isGizmo(f)]
        if gizmos:
            return gizmos
    return False

def deselectAll():
    # deselect all nodes.
    for i in nuke.allNodes():
        i.knob('selected').setValue(False)
        
def convertGizmoToGroup(gizmo):
    # convert a gizmo to an identical group.
    # delete the original, reconnect the group in the chain.
    # rename the group to match the original.
    inputs = []
    for x in range(0, gizmo.maximumInputs()):
        if gizmo.input(x):
            # print 'input: %s' % (gizmo.input(x).knob('name').value())
            inputs.append(gizmo.input(x))
        else:
            inputs.append(False)
    origName = gizmo.knob('name').value()
    origPosX = gizmo.xpos()
    origPosY = gizmo.ypos()
    deselectAll()
    # select knob, then run gizmo.makeGroup()
    gizmo.knob('selected').setValue(True)
    newGroup = gizmo.makeGroup()
    deselectAll()
    # delete original
    nuke.delete(gizmo)
    newGroup.knob('name').setValue(origName)
    newGroup['xpos'].setValue(origPosX)
    newGroup['ypos'].setValue(origPosY)
    # disconnect old inputs
    # reconnect inputs
    for x in range(0, newGroup.maximumInputs()):
        newGroup.setInput(x,None) 
        if inputs[x]:
            newGroup.connectInput(x, inputs[x])
        # print 'connecting output: %s to input: %s' % (inputs[x].knob('name').value(), newGroup.input(x).name())
    return newGroup
    
def convertGizmosToGroups():
    gizmos = getGizmos()
    if gizmos:
        for i in gizmos:
            convertGizmoToGroup(i)

There’s four methods here: first, a method to determine whether or not a node is a gizmo (by looking for a “gizmo_file” knob). Second, a method to find all gizmos by running isGizmo on every node in nuke.allNodes(). Third, the big function that does most of the heavy lifting. There’s a built-in API call that can run on gizmos called makeGroup() but by itself it’s not incredibly useful; it just wedges a converted copy of your Gizmo into the flow without doing anything to the original node, and it doesn’t name the group or anything. So this script is just adding onto that API call.

The first few lines of convertGizmoToGroup are creating an array of inputs so that we know what nodes are connected to the inputs of the gizmo. We’re just grabbing references to each input and stuffing it into the array. Next we record the name and position in the node graph of the original gizmo. We deselect everything and then set the “selected” knob of the gizmo to “True” (why we don’t have a real selection API call in Nuke, I’ll never know). Then we run the magic gizmo.makeGroup() command, which converts the gizmo into a group, but potentially leaves inputs disconnected, doesn’t delete the original gizmo, and doesn’t rename the new group. We do that in the next few lines; first deleting the original, then renaming our newGroup to match the original name, then setting the node graph position of the new group to match the original’s so it doesn’t mess up your organization. Finally, we loop through our array of inputs and connect them (in order) to the new group node. Pretty simple!

The last function is just a loop that converts every gizmo in the scene. You could import this module using menu.py and turn it into a button on a toolbar to quickly convert the whole scene from gizmos to groups by calling convertGizmosToGroups.

Hope it’s useful!

Jul 082011
 

So a while ago I worked on a project that involved a lot of work in Fume and Krakatoa, both dynamics plugins for 3DSMax. I’m not a Max user at all, nor do I know a whole lot about dynamics, but I do know these plugins are a lot better than Maya’s nParticles and fluid systems.  We had a guy come in who wanted to do all the simulation using Max, but our studio is a Maya studio. We needed a way to get all of the animation data into Max, in world space.

I wrote hfMaya2MaxFBX to quickly bake out animation data and cameras and export it into the FBX format for use in Max. It’ll also work with Nuke in most cases, since Nuke can read FBX files.

The script is split into a procedure for baking transform animation and cameras, and another to bake skin deformations. Baking transform animation is easy… we make a locator for each animated transform, constrain the locator to it, bake all channels, then delete all incoming connections and keys on the original object and parent constrain it back to the locator. Then we bake THOSE channels. The result is a cheap way of moving all the animation into world space, so we can guarantee everything is in the right place.

Baking skins is a little different… we use geometry caches to handle skin deformation. However, we still need to make sure everything is in world space for this to work. The solution is a little heavy-handed but it works for everything but the heaviest scenes: duplicate the skin, move it to world space (unparent it), then wrap deform it to the original, and finally create a geometry cache. In order for the FBX exporter to package the mesh with the geometry cache, a Quick Select Set has to be created called “objectName_set”.

The whole process is a huge pain in the ass, but with this script it’s just a matter of waiting for everything to bake. Now you can spend all that extra time surfing Reddit doing better work!

Here’s the script: hfMaya2MaxFBX.mel (right click > Save As)

To run it, just source the script and then run:

hfMaya2MaxFBX();

Hope it’s useful!