NUKE: Python & TCL Scripts & Tricks
TCL & EXPRESSIONS
Folder where the script is saved: [file root]
Root dir: [file dirname [knob [topnode].file]]
File name: [file tail [knob [topnode].file]]
File extension: [file extension [knob [topnode].file]]
Text node shot name and frame # TCL expression: [lrange [split [file tail [knob [topnode].file]] _ ] 0 0 ] :: frame [frame]
Random Expression:
main idea: min+random(frame)*(max-min)
example (random value between 100 & 300): rint(100+random(frame)*(300-100))
Setting up write nodes for specific frame range – different approaches:
Example 1: on the write node add expression: !inrange(frame, first_frame, last_frame)
Example 2: on the disable node add expression: ((frame < Read1.first)?true:false)||((frame > Read1.last)?true:false)
Using the Expression node to clamp specific values or generate mattes:
Clamping Values: On each color channel of the expression node: Color <High Value? Color:New Value Example: r<1.1?r:.9
Creating Mattes: On each color channel: Color >High Value ? Color :0 Example: r>1.1?r:0
Place an additional expression node below the first expression and under the alpha add r+g+b to consolidate the result into one matte
How to write tcl code inside a python script:
nuke.tcl(‘tcl expression here’)
For example:
nuke.tcl(‘file dirname [knob root.name]’)
Expression to generate an HD resolution stmap with a single expression node:
expression 1 (turn off green and blue): (x%1920)/1920
expression 2 (turn off red and blue): (y%1080)/1080
PYTHON SCRIPTS INDEX
- Check write nodes and create folders if none found
- Attach a Furnace DeNoise node to selected nodes
- Attach a Write node to selected Read nodes, and embed with expression on disable
- Change single or muliple parameters in all selected nodes
- Create Write nodes connected with all selected read nodes with correct file name
- Disable “Postage Stamps” on all nodes
- Unhide all nodes’ inputs (if received a script that hides them)
- Change the first frame to a certain number – enhanced version should change the last frame to that number + frame range
- Print a selected nodes’ methods
- Find all the Timeoffset nodes in a group (called group2) and change value of offset based on its position in an array of found time offsets
- Remove all animation from selected nodes
- Add keyframes – Animate mix parameter
- Halve the color value of all constant nodes in a script
- Find all the transform Nodes in the script and if their input is a crop set scale value X2
- Set all gain values of CC nodes X2
- Change font size of all Write nodes in the script
- Create 20 constants with incrementing color values
- Set up write nodes for specific frame range
- Use Python to define your own hotkeys
- Select all class nodes (class Read in this case)
- Write DPX, create Slate and WriteJPG generator – written for Method Pipeline
- Camera with aim TCL
- Add a text node with the value from the input node
- Multiple Read/Write nodes tweaker
- Import mocha track and create a normal and reversed corner pin out of it
- Control / smooth curves with a multiplier
- Open all property bins of all selected nodes
- Write all the read nodes file name in the script editor
- Add a text node with the value from the input node
1. Check write nodes and create folders if none found
# script that checks if write nodes have folders # and creates them if not import os import sys import os.path from os import system from os import makedirs import nuke this_filename = sys._getframe().f_code.co_filename print('Loading '+this_filename) def write_mkdir(nodes = ''): 'Make directories from write nodes' n = nuke.allNodes() for i in n: if i.Class() == "Write": i.knob("selected").setValue(True) snodes = nuke.selectedNodes() if len(snodes) == 0: nuke.message('ERROR: No Write nodes to work on') return for i in snodes: _class = i.Class() if _class == "Write": # use this to get only the filename path = nuke.filename(i) if empty continue if path is None: continue # Get Directory Structure with out file name dirPath = os.path.dirname(path) if os.path.isdir (dirPath): nuke.message('Directory already exists:\n%s' % (dirPath)) continue if os.path.isfile (dirPath): # The folder exists as a file msg = "The directory:\n%s\nexists as a file. Delete it and create folder?" % (dirPath) delete_existing_file = nuke.ask(msg) if (delete_existing_file): os.unlink (dirPath) else: return # Create directory try: makedirs(dirPath,0775) nuke.message('Created:\n%s' % (dirPath)) except: if nuke.ask('Create Path: '+ dirPath): makedirs(dirPath,0775) continue else: return else: nuke.message('ERROR: Skipping non-Write node.') continue return
2. Attach a Furnace DeNoise node to selected nodes
# script that attaches a Furnace DeNoise node # with default values to selected nodes, # and then adds a write node to that Furnace DeNoise node sn = nuke.selectedNodes() for n in sn: first = n.firstFrame() last = n.lastFrame() a = n['file'].value() b = n['name'].value() c = a.replace('.%04d.dpx','_denoise.%04d.exr') d = "DeNoise_"+b dn=nuke.nodes.F_DeNoise (name=d, plateSize="Pal Or NTSC") dn.setInput(0,n) nuke.toNode(d).knob('selected').setValue(True) wr = nuke.nodes.Write (name="Write_EXR",file=c, colorspace="linear") wr['disable'].setExpression("((frame < "+b+".first)?true:false)||((frame >"+b+".last)?true:false)") wr.setInput(0,dn)
3. Attach a Write node to selected Read nodes, and embed with expression on disable
# script that attaches a Write node with default values to selected Read nodes # and sticks an expression that reads first and last frames from the read notes sn = nuke.selectedNodes() for n in sn: first = n.firstFrame() last = n.lastFrame() a = n['file'].value() b = n['name'].value() # c = a.replace('.%04d.sgi','%04d.'+fmt) d = "DeNoise_"+b wr = nuke.nodes.Write(name="WriteFromRead",file=c, colorspace="sRGB") wr['disable'].setExpression("((frame < "+b+".first)?true:false)||((frame >" +b+".last)?true:false)") wr.setInput(0,n)
4. Change single or multiple parameters in all selected nodes
# SCRIPT THAT CHANGES SINGLE OR MULTIPLE PARAMETERS IN ALL SELECTED NODES sn = nuke.selectedNodes() for n in sn: n.knob('channels').setValue("rgba") n.knob('colorspace').setValue("sRGB") #script that adds a text node with the value from the input node. sn = nuke.selectedNodes() for i in sn: txt = nuke.nodes.Text (font ="/usr/share/fonts/bitstream-vera/Vera.ttf", message = "[file tail [knob input0.file]]", size = "35") txt.knob[transform.box].setValue(0,0,1920,1080) txt.setInput(0,i)
5. Create Write nodes connected with all selected read nodes with correct file name
# MAKE WRITE NODES CONNECTED WITH READ NODES WITH THE CORRECT FILE NAME sn = nuke.selectedNodes() for n in sn: a = n.name() f = n['name'].value() wsgi=nuke.nodes.Write(name='SGI_Write', file=f, colorspace='default') wsgi['file_type'].setValue("sgi") wsgi['channels'].setValue("rgba") wsgi.setInput(0,n)
6. Disable “Postage Stamps” on all nodes
# DISABLE "POSTAGE STAMPS" ON ALL NODES for a in nuke.allNodes(): try: a['postage_stamp'].setValue(0) except: pass
7. Unhide all nodes’ inputs (if received a script that hides them)
# "UNHIDE" ALL NODES' INPUTS - USEFUL WHEN RECEIVING A SNEAKY COMP/LIGHTING SCRIPT for a in nuke.allNodes(): try: a['hide_input'].setValue(0) except: pass
8. Change the first frame to a certain number – enhanced version should change the last frame to that number + frame range
# CHANGE THE "FIRST" FRAME OF ALL SELECTED NODES THAT ARE READ NODES # (EXAMPLE CHANGES THE FIRST FRAME TO 1001) for a in nuke.selectedNodes(): if a.Class() == 'Read': a['first'].setValue(1001)
9. Print a selected nodes’ methods
# PRINT A SELECTED NODES' METHODS import struct node = nuke.selectedNode() for a in node['lookup'].animations(): print dir(a) print inputs (dependencies) of a selected node: for a in nuke.selectedNode().dependencies(): print a.name() print outputs (dependents) of a selected node: for a in nuke.selectedNode().dependent(): print a.name()
10. Find all the Timeoffset nodes in a group (called group2) and change value of offset based on its position in an array of found time offsets
# FIND ALL THE TimeOffset NODES IN A GROUP CALLED "Group2", AND CHANGE THE VALUE # OF EACH OFFSET BASED ON ITS POSITION IN THE ARRAY OF FOUND TIME OFFSETS tos = [] for a in nuke.toNode('Group2').nodes(): if a.Class()=='TimeOffset': tos.append(a) for b in tos: b['time_offset'].setValue(tos.index(b)) set the ‘bbox’ for any selected Merge, Keymix & Copy nodes to “B” for a in nuke.selectedNodes(): classTypes = ['Merge' , 'Keymix', 'Copy', ] for n in classTypes: if n in a.Class(): for p in a['bbox'].values(): if 'B' in p: a['bbox'].setValue(a['bbox'].values().index(p))
11. Remove all animation from selected nodes
# REMOVE ALL ANIMATION FROM SELECTED NODES for a in nuke.selectedNodes(): for b in a.knobs(): a[b].clearAnimated()
12. Add keyframes – Animate mix parameter
# ADD KEYFRAMES - ANIMATE A MIX for a in nuke.selectedNodes(): a['mix'].setAnimated() a['mix'].setValueAt(1,nuke.frame()) a['mix'].setValueAt(0,(nuke.frame() - 1))
13. Halve the color value of all constant nodes in a script
# HALVE THE COLOR VALUE OF ALL THE CONSTANT NODES IN A SCRIPT for a in nuke.allNodes(): if a.Class() == "Constant": a['color'].setValue(a['color'].value()[0] / 2 , 0) a['color'].setValue(a['color'].value()[1] / 2 , 1) a['color'].setValue(a['color'].value()[2] / 2 , 2)
14. Find all the transform Nodes in the script and if their input is a crop set scale value X2
# FIND ALL THE TRANSFORM NODES IN A SCRIPT, AND IF THEIR INPUT IS A CROP SET THE SCALE # VALUE TO BE TWICE ITS CURRENT VALUE (ALSO CHECKS IF THE SCALE IS A LIST ARRAY OR A FLOAT) for a in nuke.allNodes(): if a.Class() == "Transform": if a.input(0).Class() == "Crop": x = a['scale'].value() if type(x).__name__ == 'list': a['scale'].setValue(x[0] * 2 , 0) a['scale'].setValue(x[1] * 2 , 1) if type(x).__name__ == 'float': a['scale'].setValue(x*2)
15. Set all gain values of CC nodes X2
# SET ALL THE GAIN VALUES OF ALL SELECTED COLOR CORRECT NODES TO TWICE THEIR CURRENT for a in nuke.allNodes(): if a.Class() == "ColorCorrect": a['gain'].setValue(a['gain'].value() * 2) print files with ‘mov’ in filename for a in nuke.allNodes(): if 'Read' in a['name'].value(): if 'mov' in a['file'].value(): print a['file'].value()
16. Change font size of all Write nodes in the script
# CHANGE FONT SIZE OF ALL WRITE NODES IN THE SCRIPT for a in nuke.selectedNodes(): if "Write" in a['name'].value(): a['note_font_size'].setValue(60)
17. Create 20 constants with incrementing color values
# CREATE 20 CONSTANTS WITH INCREMENTING COLOR VALUES def makeConstants(amount): for i in range(amount): a= nuke.nodes.Constant() color= float( float(i) / float(amount) ) a['color'].setValue(color)
18. Set up write nodes for specific frame range
# SET UP WRITE NODES FOR SPECIFIC FRAME RANGE sn = nuke.selectedNodes() for n in sn: first = n.firstFrame() last = n.lastFrame() nuke.render( n.name(), first, last, 1 )
19. Use Python to define your own hotkeys
#DEFINING YOUR OWN HOTKEYS def _autoplace(): n = nuke.selectedNodes() for i in n: nuke.autoplace(i) t=nuke.toolbar("Extras") t.addCommand("Auto&place", "_autoplace()", "Alt+a")
20. Select all class nodes (class Read in this case)
#SELECTING ALL CLASS NODES (READ NODES) n = nuke.allNodes() for s in n: if s.Class() == "Read": s.knob("selected").setValue(True)
21. Write DPX, create Slate and WriteJPG generator – written for Method Pipeline
#WRITE DPX, SLATE AND WRITE JPG # writeDPX, slate and writeJPG generator v0.1 alpha # 1. delete the old write_DPX, slate and write_Latest nodes # 2. click on the last node in your comp (select it) # 3. execute script a="[file dirname [value root.name]]/../../images/comp/[file rootname [file tail [value root.name]]]/[file rootname [file tail [value root.name]]].%04d.dpx" b="[file rootname [file tail [value root.name]]].[frame].dpx" c="[file dirname [value root.name]]/../../images/comp/latest/[lindex [split [value root.name] /] 4]_comp_latest.%04d.jpg" wdpx=nuke.nodes.Write(name="Write_DPX", file=a, colorspace="rec709") wdpx['file_type'].setValue("dpx") wdpx.setInput(0,nuke.selectedNode()) nuke.toNode('Write_DPX').knob('selected').setValue(True) wslate = nuke.nodes.Text (name="Slate", font="/usr/share/fonts/bitstream-vera/Vera.ttf", yjustify = "center") wslate['box'].setValue([0,0,2048,1168]) wslate['translate'].setValue([50, -550]) wslate['size'].setValue(25) wslate['message'].setValue(b) wslate.setInput(0,nuke.selectedNode()) nuke.toNode('Slate').knob('selected').setValue(True) wjpg=nuke.nodes.Write (name="Write_Latest", file=c, colorspace="rec709") wjpg['file_type'].setValue("jpg") wjpg['_jpeg_quality'].setValue([1]) wjpg.setInput(0,nuke.selectedNode())
22. Camera with aim
# camera with aim for Nuke v0.1 by Aleksandar Djordjevic n = nuke.nodes.Camera2() p = 'set lookAt [value lookObject]\n puts $lookAt\n set xX "degrees(atan2($lookAt.translate.y-translate.y,sqrt(pow($lookAt.translate.x-translate.x,2)+pow($lookAt.translate.z-translate.z,2))))"\n set yX "$lookAt.translate.z-this.translate.z >= 0 ? 180+degrees(atan2($lookAt.translate.x-translate.x,$lookAt.translate.z-translate.z)):180+degrees(atan2($lookAt.translate.x-translate.x,$lookAt.translate.z-translate.z))"\n in this.rotate.x {set_expression $xX}\n in this.rotate.y {set_expression $yX}\n' tab = nuke.Tab_Knob("Look","Camera Aim") n.addKnob(tab) k = nuke.Script_Knob("knob", "look at") n.addKnob(k) n.knob("knob").setValue(p) k.setTooltip('Press this button after you type in the aim object\'s name') m = nuke.String_Knob("lookObject", "") n.addKnob(m).po m.setTooltip('Type your aim object node name here')
23. Add a text node with the value from the input node
#script that adds a text node with the value from the input node. sn = nuke.selectedNodes() for i in sn: txt = nuke.nodes.Text (font ="/usr/share/fonts/bitstream-vera/Vera.ttf", message = "[file tail [knob input0.file]]", size = "35") txt.knob[transform.box].setValue(0,0,1920,1080) txt.setInput(0,i)
24. Multiple Read/Write node tweaker
# multi node tweaker v0.1 by Aleksandar Djordjevic # # this script creates a panel that enables the user to manipulate # several knobs inside all selected read and write nodes # you can select all nodes but it is going to change values only on reads and writes\ import nuke import os def multiNodeTweaker(): test = 0 origFileName = None replaceInFileName = None booleanCheckBox = None chanVal = 'rgb rgba alpha depth' cspace = 'default linear sRGB rec709 Cineon Gamma1.8 Gamma2.2 Panalog REDlog ViperLog REDSpace' sn = nuke.selectedNodes() # first checkpoint - is anything selected? if (len(sn) == 0): nuke.message("Select one or more Read or Write nodes") return # second checkpoint - I will work only on valid node classes for i in sn: if i.Class() != 'Read' or 'Write': nuke.message("No Read or Write nodes selected.") return o = nuke.Panel("Multi Node Tweaker") o.addSingleLineInput('Find:', origFileName) o.addSingleLineInput('Replace:', replaceInFileName) o.addEnumerationPulldown('Color Space',cspace) o.addButton("Cancel") o.addButton("Ok") # If selected nodes are of Write class, add parameter to mess with the channels for i in sn: if i.Class() == 'Write': test = 1 if test == 1: o.addEnumerationPulldown('Channels:',chanVal) o.show() # grab new values origFileName = o.value("Find:") replaceInFileName = o.value("Replace:") cspace = o.value("Color Space") chanVal = o.value("Channels:") for n in sn: filename = n['file'].value() newFileName = filename.replace(origFileName,replaceInFileName) n.knob('file').setValue(newFileName) n.knob('colorspace').setValue(cspace) if n.Class() == 'Write': n.knob('channels').setValue(chanVal)
25. Import mocha track and create a normal and reversed corner pin out of it
import nuke, os def importMocha(): filename = nuke.getFilename("Mocha tracking data", "*.txt") f = open(filename) row = -1 active = False data = [] height = 0 for l in f.readlines(): items = l.split() if len(items) < 1: active = False if l.lower().lstrip().startswith("source height"): height = float(items[2]) if active: data[row].append(items) if l.lower().lstrip().startswith("frame"): row += 1 active = True data.append([]) cornerPinNode = nuke.createNode("CornerPin2D") cornerPinReverseNode = nuke.createNode("CornerPin2D") points = ["1", "2", "4", "3"] for c in range(4): #cornerPinNode.knob("to" + str(c + 1)).setAnimated(True) toKnob = cornerPinNode.knob("to" + points[c]) fromKnob = cornerPinReverseNode.knob("from" + points[c]) for k in (toKnob, fromKnob): k.setAnimated(0, True) k.setAnimated(1, True) for (f, x, y) in data[c]: k.setValueAt(float(x), float(f), 0) k.setValueAt(height - float(y), float(f), 1)
26. Control / smooth curves with a multiplier
Create a node, let's say a camera node. Create a user tab on it, and make a floating point slider called multiplier and labeled multiplier. Then, in the expression of your x,y,z for translate, rotate, scale, whatever you want to smooth and control punch in this expression: curve-(curve * multiplier) For every frame, it will subtract that frame's value with your multiplier, and if it's 0, it's your original value, if it's not, it changes and smooths the curve by a [multiplier] factor.
27. Open all property bins of all selected nodes
# open all property bins of all selected nodes # set the max panels number to the amount of nodes you selected import nuke, os def selnode(): sn = nuke.selectedNodes() maxPanels = nuke.toNode('preferences')['maxPanels'] panelCount = 0 for i in sn: panelCount = panelCount+1 if panelCount > maxPanels.value(): maxPanels.setValue(panelCount) for n in sn: nuke.show(n)
28. Write all the read nodes file name in the script editor
# write all the read nodes file names in the script editor for a in nuke.allNodes(): if 'Read' in a['name'].value(): print a['file'].vaue()
29. Add a text node with the value from the input node
#script that adds a text node with the value from the input node. sn = nuke.selectedNodes() for i in sn: txt = nuke.nodes.Text (font ="/usr/share/fonts/bitstream-vera/Vera.ttf", message = "[file tail [knob input0.file]]", size = "35") txt.knob[transform.box].setValue(0,0,1920,1080) txt.setInput(0,i)