Nuke Basic
- store your pre-set node setting video guide
action | shortcut, cmd=ctrl |
open node property | double-click, cmd+click, return |
open node property float | cmd+double-click, cmd+alt+click |
close all property | alt+click on x on panel |
Nuke Intro
Tracking in Nuke
- tracker node:
- 2D for translation, rotation, scale
- require: 1 point for translation, 2 points for rotation and scale
- planar tracker node:
- 2.5D for translation, rotation, scale, skew, perspective
- require: a planar surface
- camera tracker node:
- 3D for volumes, spaces, planes, perspective in 3D
- require: focal length, film back size, camera parallax movement, lens distortion removal
Removal and Paint in Nuke
- prepare footage
- grain/noise removal (denoise node)
- stabilize
- choose clear reference frame
- get BBox coverage
- frameHold portions and paint node groups
- shape parts to relieve
- matchmove and add grain
Camera Track and Projection in Nuke
- solve camera in nuke or other app
- 3D camera in nuke
- Geometry
- Clean Patch
- Frozen Camera
Nuke Python Script Intro
Where to enter the script
- x key: (File > Script Command - TCL/Python)
- script editor: (Right click the panel bar > split vertical and choose “Script Editor” in drop down)
- Error console
Where to view command history (like Maya “Echo all Command”)
- Edit menu > Preference : Script Editor tab : Echo python command
Where to know the node or knob attribute name
- right click on the attribute and click “Add Expression”, then all the internal name releaved.
How to know the node Class and Function
- use this code
your_node.Class() # to get Class name help(your_node.Class()) # to get class definition
Ultimate solution: Python Panels
- a script based python-based floating tab panel that integrated with Nuke, not a dialog
Nuke Python common syntax
- common python syntax
i=0; list=[] list.append(item) print list total = len(list) - 1 print total for i in range(0, total): print list[i]
Interact with Nuke GUI interface
ref: http://www.youtube.com/watch?v=JoniI7oRDaU
for the code not working, just clean the space and use tab to re-create the tabs
Tips: if you want to know the knob name, then hold Alt+drag it to script editor to show its reference name.
- get and feedback to user
nuke.message("hello") # alert box nuke.tprint("it prints in terminal where nuke launched from")
- get selected node
nuke.selectedNodes() # return a list nuke.toNode('NodeName') # get node with the name
- get format and node format
node = nuke.selectedNode() nodeFormat = node.format() print nodeFormat.name() #or width nuke.selectedNode().width() nuke.selectedNode().height() # or all formats scriptFormats = nuke.formats() for f in scriptFormats: print f.name() print f.width() print f.height() print f.pixelAspect() print 10*'-'
- get select node knobs (cool way for GUI programming of existing node)
znodes=nuke.selectedNodes() znode=znodes[0] for i in range(znode.getNumKnobs()): print '"%d %s' % (i, znode.knob (i).name()) # method 2 help(nuke.selectedNode()) #list all node method nuke.selectedNode().Class() #print node class name # qwidget under mouse from PySide import QtGui,QtCore def getPos(): pos = QtGui.QCursor.pos() widget = QtGui.qApp.widgetAt(pos) print(widget) QtCore.QTimer.singleShot(5000, getPos) # print widget under mouse after 5s # all panel nuke.Double_knob parent_window = QtGui.QApplication.activeWindow() all_stacked_widgets = parent_window.findChildren(QtGui.QStackedWidget)
- get active knob from right click on knob
knobMenu = nuke.menu("Animation") knobMenu.addCommand('Set Key knob', "nuke.message(\"Knob Name: nuke.toNode('%s').knob('%s'); %s\" % (nuke.thisNode().name(), nuke.thisKnob().name(), nuke.thisKnob().value()) );keyNode=nuke.thisNode().name()+'.'+nuke.thisKnob().name();" ) topMenu = nuke.menu('Nuke') topMenu.addCommand('Test/Key knob', "nuke.message('keying now: %s' % keyNode);keyCurrent(keyNode)", 'Ctrl+F11' ) def keyCurrent(node_attr): # node_attr format: node.attr info = node_attr.split('.') keyNodeAttr = nuke.toNode(info[0]).knob(info[1]) cur_frame = nuke.frame() cur_value = keyNodeAttr.value() if not keyNodeAttr.isAnimated(): keyNodeAttr.setAnimated() keyNodeAttr.setValueAt(cur_value, cur_frame)
- get or set gui value
print znode.knob ('knobName').value() print znode['knobName'].value() znode.knob (i).setValue('theValue')
- write to file and read from file
import sys import os filename='/home/user/TrackConvertSrc.txt' fp = open(filename, 'w') fp.write( "0 0 0\n" ) trackSrcX = znode.knob('to1').animation(0) for key in trackSrcX.keys(): if flipY: fp.write( "%g %g %g\n" % (key.x, key.y, imageHeight - trackSrcY.evaluate( key.x )) ) else: fp.write( "%g %g %g\n" % (key.x, key.y, trackSrcY.evaluate( key.x )) ) fp.close() # read trackDst = znode.knob('to1') trackDst.clearAnimated(0) trackDst.clearAnimated(1) trackDst.setAnimated(0) trackDst.setAnimated(1) trackX = trackDst.animation(0) trackY = trackDst.animation(1) fp = open(filename, 'r') for line in fp: if line.startswith('0'): continue try: tt, xx, yy = [float(x) for x in line.split()] except: continue trackX.setKey( tt, xx ) if flipY: trackY.setKey( tt, imageHeight - yy ) else: trackY.setKey( tt, yy ) fp.close()
- deal with 2D position animation curve (pre-baked curve required)
# like znode as cornerPin node # read curve trackSrc = znode.knob('to1') if not trackSrc.isAnimated(0) or not trackSrc.isAnimated(1) : nuke.message('source track no keyframes!') trackSrcX = trackSrc.animation(0) trackSrcY = trackSrc.animation(1) # write curve
- node creation related
# method 1 newNode=nuke.nodes.CornerPin2D(name='newCorner') # method 2 nuke.createNode('CornerPin2D') # get selected node type or class name znodes=nuke.selectedNodes() znode=znodes[0] znode.Class() # Tracker3
- node attributes related
imageHeight = znode.height() imageWidth = znode.width() format = znode.format().name() pixelAspect = znode.format().pixelAspect() # create attribute experssion # example: tracker to crop mode fullTracker="Track1" # tracker node crop="Crop1" #crop node newName=fullTracker+"_crop_mode" newNode=nuke.nodes.Tracker3(name=newName) newNode['enable1'].setValue(True) newNode['enable2'].setValue(True) newNode['enable3'].setValue(True) newNode['enable4'].setValue(True) newNode['track1'].setExpression(fullTracker+'.track1-'+crop+'.box.x', 0) newNode['track1'].setExpression(fullTracker+'.track1-'+crop+'.box.y', 1) newNode['track2'].setExpression(fullTracker+'.track2-'+crop+'.box.x', 0) newNode['track2'].setExpression(fullTracker+'.track2-'+crop+'.box.y', 1) newNode['track3'].setExpression(fullTracker+'.track3-'+crop+'.box.x', 0) newNode['track3'].setExpression(fullTracker+'.track3-'+crop+'.box.y', 1) newNode['track4'].setExpression(fullTracker+'.track4-'+crop+'.box.x', 0) newNode['track4'].setExpression(fullTracker+'.track4-'+crop+'.box.y', 1)
- animation related
curNodeAttr = nuke.toNode("Grade1")['blackpoint'] animCuves = curNodeAttr.animations() curAnimCurve = curNodeAttr.animation(0) # get value at frame valueAtFrame1 = curAnimCurve.evaluate(2) # value at frame 2 # set value at frame curAnimCurve.setKey(10, 0.5) # set to 0.5 at frame 10 # check value expression curNodeAttr.hasExpression() # 1,0 curAnimCurve.noExpression() # 1,0 # set expression connection animCurveB.setExpression('blackpoint') # get expression exp = curAnimCurve.expression() # get key keys = curAnimCurve.keys() curAnimCurve.addKey(keys) curAnimCurve.clear() # same as nuke.animation("Grade1.blackpoint", "clear")
- plugins
nuke.pluginPath() # list all plugin path, use first found in path nuke.pluginAddPath(os.path.abspath("/my/path")) # all os compatile
menu.py
Nuke menu customization
- put menu.py in “.nuke” folder (which is under home directory)
- sample code of import a py file GUI tool in menu.py file
import sys; sys.path.insert(0, "/myPythonScriptDir/dev/") import MyPythonFileNameOnly as myFirstGUI m = menubar.addMenu("MyCustMenu") m.addCommand("Menu Item Name", "myFirstGUI.go()")
- menu.py can also be used to change/add menu shortcut (read reference)
- menu.py can also be used to set node default setting (read reference)
- sample code of Python GUI tool for menu integration
import nuke import nukescripts class myFirstGUI(nukescripts.panels.PythonPanel): def __init__(self, name): nukescripts.panels.PythonPanel.__init__(self, name) # gui preset newline = nuke.Text_Knob("") newline.setVisible(False) self.btn01=nuke.PyScript_Knob("firstBtn", "My button") self.addKnob(self.btn01) self.addKnob(newline) self.addKnob(nuke.PyScript_Knob("AskBtn", "Hello Button", "nuke.message(\"Done by Me v1.0! \\n\\nv1.0 usage:\\n- Do it.\")")) def knobChanged( self, knob ): if knob == self.btn01: print("cool") def go(): mypanel = myFirstGUI("GUI cool v1.0") mypanel.show()
Python-Panel GUI design
- ref here:
- custom panel guide: http://docs.thefoundry.co.uk/nuke/63/pythondevguide/custom_panels.html
- common GUI element
p = nuke.Panel('My Pop-up Panel') p.addButton("cool") result = p.show()
- built-in GUI panel_test
from nukescripts import panel_test panel_test.panel_example()
- tab window template
class modelPanel(nukescripts.panels.PythonPanel): def __init__(self, name): nukescripts.panels.PythonPanel.__init__(self, name) #================= self.addKnob(nuke.Text_Knob("Group1")) newline = nuke.Text_Knob("") newline.setVisible(False) self.addKnob(nuke.PyScript_Knob("btn01", "Label01", "nuke.message(\"hey\")" )) self.addKnob(newline) self.addKnob(nuke.PyScript_Knob("btn02", "Label02", "nuke.message(\"hey\")" )) self.addKnob(newline) #================= self.addKnob(nuke.Text_Knob("Group2")) self.addKnob(nuke.PyScript_Knob("btn03", "Label03", "nuke.message(\"hey\")" )) self.addKnob(newline) #================= self.addKnob(nuke.Text_Knob("Group3")) self.addKnob(nuke.PyScript_Knob("btn04", "Label04", "nuke.message(\"hey\")" )) self.addKnob(newline) #========== show up script run seperately panel = None global panel if not panel: panel = modelPanel("Model Select Panel") panel.show()
- GUI knob button with multi-line pop-up message
self.addKnob(nuke.PyScript_Knob("HelpBtn", "Tip*Trick", "nuke.message(\"\\n1.ask me line 1.\\n2.check my update line2.\")"))
My Nuke Python Script tools
Example of procedure GUI design
- tracker in full resolution image into crop reformat image
#============================ # Full-Res Tracker to Crop Tracker by yx v1.0 # Input : name of tracker and crop node # Output: new tracker node with linked corresponding tracker data in crop mode # 2014.02.15 #============================ import nuke def go(): p = nuke.Panel('Full-Res Tracker to Crop Tracker by yx v1.0') p.addSingleLineInput('Full-Res Tracker Node', '') p.addSingleLineInput('Crop Node', '') p.addButton('Cancel') p.addButton('Generate Crop Tracker Node') ret = p.show() fullTracker = p.value('Full-Res Tracker Node') crop = p.value('Crop Node') if ret: print fullTracker, crop newName=fullTracker+"_crop_mode" newNode=nuke.nodes.Tracker3(name=newName) print newName+" created" newNode['enable1'].setValue(True) newNode['enable2'].setValue(True) newNode['enable3'].setValue(True) newNode['enable4'].setValue(True) newNode['track1'].setExpression(fullTracker+'.track1-'+crop+'.box.x', 0) newNode['track1'].setExpression(fullTracker+'.track1-'+crop+'.box.y', 1) newNode['track2'].setExpression(fullTracker+'.track2-'+crop+'.box.x', 0) newNode['track2'].setExpression(fullTracker+'.track2-'+crop+'.box.y', 1) newNode['track3'].setExpression(fullTracker+'.track3-'+crop+'.box.x', 0) newNode['track3'].setExpression(fullTracker+'.track3-'+crop+'.box.y', 1) newNode['track4'].setExpression(fullTracker+'.track4-'+crop+'.box.x', 0) newNode['track4'].setExpression(fullTracker+'.track4-'+crop+'.box.y', 1)
Example of Class like GUI design
- copy BoundBox to CornerPin setting
#============================ # BBox_Pin v1.0 # pin placed directly to bbox of the node # #============================ p1x=0 p1y=0 p2x=0 p2y=0 p3x=0 p3y=0 p4x=0 p4y=0 class bboxPinPanel(nukescripts.panels.PythonPanel): def __init__(self, name): nukescripts.panels.PythonPanel.__init__(self, name) # gui preset newline = nuke.Text_Knob("") newline.setVisible(False) self.btn01=nuke.PyScript_Knob("CopyBtn", "Copy BBox") #btn01.setCommand("copyBBox()") self.addKnob(self.btn01) self.btn02=nuke.PyScript_Knob("PasteBtn", "Paste to Pin") self.addKnob(self.btn02) def knobChanged( self, knob ): if knob == self.btn01: global p1x global p1y global p2x global p2y global p3x global p3y global p4x global p4y znode = nuke.selectedNode() print znode.name() bh=znode.bbox().h(); bw=znode.bbox().w(); bx=znode.bbox().x(); by=znode.bbox().y(); p1x=bx p1y=by p2x=bx+bw p2y=by p3x=bx+bw p3y=by+bh p4x=bx p4y=by+bh print [p1x,p1y,p2x,p2y,p3x,p3y,p4x,p4y,] if knob == self.btn02: global p1x global p1y global p2x global p2y global p3x global p3y global p4x global p4y znode = nuke.selectedNode() znode["to1"].setValue(p1x,0) znode["to1"].setValue(p1y,1) znode["to2"].setValue(p2x,0) znode["to2"].setValue(p2y,1) znode["to3"].setValue(p3x,0) znode["to3"].setValue(p3y,1) znode["to4"].setValue(p4x,0) znode["to4"].setValue(p4y,1) znode["from1"].setValue(p1x,0) znode["from1"].setValue(p1y,1) znode["from2"].setValue(p2x,0) znode["from2"].setValue(p2y,1) znode["from3"].setValue(p3x,0) znode["from3"].setValue(p3y,1) znode["from4"].setValue(p4x,0) znode["from4"].setValue(p4y,1) bppanel = bboxPinPanel("BBox to PinPoint by Ying v1.0") bppanel.show()
- roto shape point access and control script
node = nuke.selectedNode() knob = node['curves'] for element in knob.rootLayer: for index, point in enumerate(element): print index, point.center.getPosition(nuke.frame()) # setPosition(CVec2(cpx, cpy))