UPDATE: A newer version of this plugin exists here.
The story goes like this. It may sound familiar.
You're working on an animation in your favorite node-based compositing application, and you want to make a timing change. The first half of the animation is perfect, but it should hold a little longer before it finishes, to better match the background plate.
Problem is, you've got animated nodes all over your script, and all of their keyframes need to move in sync. Transform nodes, Grade nodes, GridWarp nodes.
You zoom in and move around your script, looking for nodes with the little red "A" in the upper right corner.
No, not that node. That one's for that other asset and it doesn't need to move.
Okay, got 'em all open? Now switch the the Dope Sheet, grab everything after frame 75 and slide it to the right a few frames. Done?
Let's watch the new timing.
Shit. Forgot one.
Which one?
Oh, here it is. Wait. How many frames did the other 6 nodes move?
Sigh.
CMD+Z
. CMD+Z
. CMD+Z
. CMD+Z
. CMD+Z
. CMD+Z
.
Okay, are they all open this time? Good. Now slide them all together.
Done? Let's watch it.
Better.
10 Minutes And 20 Additional Nodes Later.
Well...now I need a little less time between frames 30 and 42.
Dammit.
Feature Request
This is the annoying scenario I found myself repeating about a dozen times on a recent project, so I sent an email to The Foundry's support team, requesting the addition of a feature I described as "Node Sets".
A Node Set is an arbitrary collection of nodes that can be opened all at once with a single command. New nodes can be added as the script grows, or removed if they're no longer needed.
Along with my feature request, I provided these two screenshots to help explain:
What I received back from Jake, my new best friend at The Foundry Support, was the following script:
# This function opens the control panels of
# all the nodes with "inNodeSet" on their label
def showOnlyChosenNodes():
for node in nuke.allNodes():
if "inNodeSet" in node['label'].value():
print node.name()
node.showControlPanel()
else:
node.hideControlPanel()
# This function adds "inNodeSet" to a
# new line on the label of all the selected nodes
def labelNodes():
for node in nuke.selectedNodes():
label = node['label'].value()
if 'inNodeSet' not in label:
node['label'].setValue( label + '\ninNodeSet')
# This function clears the label of
# all the selected nodes
def unLabelNodes():
for node in nuke.selectedNodes():
label = node['label'].value()
if 'inNodeSet' in label:
node['label'].setValue( label.replace('\ninNodeSet','') )
# These commands create a new menu item with
# entries for the functions above
nuke.menu('Nuke').addCommand('Node Sets/Show Nodes in Set', "showOnlyChosenNodes()")
nuke.menu('Nuke').addCommand('Node Sets/Add Selected Nodes to Set', "labelNodes()")
nuke.menu('Nuke').addCommand('Node Sets/Remove Selected Nodes from Set', "unLabelNodes()")
For those of you who don't speak Python, allow me explain what's happening here. Once added to your Menu.py
file, the script creates 3 tools in a new menu within Nuke.
Just as I requested, I have the ability to add or remove selected nodes from the group, then, when I need to make a change, open all of those nodes with a single command.
Magic.
Not Magic
What the script is actually doing is tagging the nodes. No, Nuke did not suddenly or secretly gain the ability to add tags to things, it's cleverly using the label
section in the Node
tab to hold the inNodeSet
text. The Show Nodes in Set
command simply scans all the nodes in your script for nodes with inNodeSet
in their labels, and opens them. Simple. Smart.
As a result, yes, you can add the inNodeSet
text to the label
field manually, rather than using the new menu command, and the Show Nodes in Set
command will find it, but who would want to do such a barbarous thing?
Customization
As with all commands in Nuke, a keyboard shortcut can be added to these commands to make the process even quicker. But, since I don't particularly enjoy cluttering up my menu bar with unnecessary menus, nor do I enjoy having more keyboard shortcuts than I can remember (I totally already do), I opted to move the commands into the Nodes
menu. This is easily done by swapping the last 3 lines of Jake's script with these lines:
toolbar = nuke.menu("Nodes")
nsets = toolbar.addMenu("Node Sets")
nsets.addCommand('Show Nodes in Set', 'showOnlyChosenNodes()')
nsets.addCommand('Add Selected Nodes to Set', 'labelNodes()')
nsets.addCommand('Remove Selected Nodes from Set', 'unLabelNodes()')
Here's where my tools now live.
I do this for one major reason; having these tools available in the Tab + Search
tool. For those unfamiliar, Nuke has a built in tool similar to Spotlight or LaunchBar that allows you to press Tab
then type the name of the tool you're looking for, avoiding the need to have keyboard shortcuts for every type of node.
Current Limitations
This being a bit of a hack, there are naturally a few limitations. First and foremost, using this tool will delete anything you already had in the label field of a node. I doesn't support the ability to add a tag to the text in the label
field. The tag has to be the only thing in the label field.
Secondly, once you realize how useful this is, you may want to have more than one Node Set at your disposal. The good news about this current limitation is that you can very easily create as many node sets as you want by duplicating the code and changing the inNodeSet
tag to something like inNodeSet2
.
Of course, with multiple node sets, it'd be ideal if you could include a given node in multiple sets at the same time, but like I mentioned, this is not a real tagging system. If real tagging ever makes its way into the application, I imagine such a thing will then be possible.
Update - 2014-06-25
I emailed my pal Jake again, telling him how much I appreciate his work on this script, and you'll never guess what he did. He sent me an updated version of the script that adds the tag to the node label
without overwriting the current text in the field.
Not only is this great for general usability, it means we can add a node to multiple Node Sets at the same time. We now have a real tagging system built into Nuke. How great is Jake? Seriously.
One thing I will note; if you are planning on using multiple Node Sets, you'll want to change the default tag to inNodeSet1
. If you leave it as inNodeSet
, it will also show up in results for other tags, like inNodeSet2
.
Attribution
If it wasn't clear before, all credit for this script goes to The Foundry and their awesome support team. They continue to be one of my favorite companies, specifically because they offer great support in addition to their great products.
I'm incredibly happy to have this annoyance removed from my workflow, and I hope you are too.