appwiki:nuke

Differences

This shows you the differences between two versions of the page.


Previous revision
appwiki:nuke [2022/10/08 07:32] (current) – [Nuke Basic] ying
Line 1: Line 1:
 +====== Nuke Basic ======
 +
 +  * store your pre-set node setting [[http://shizukalog.blogspot.com/2010/11/nuke-setting-up-default-parameter-of.html|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 <code python> your_node.Class() # to get Class name
 +help(your_node.Class()) # to get class definition
 +</code>
 +
 +**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 <code python>
 +i=0;
 +list=[]
 +list.append(item)
 +print list
 +total = len(list) - 1
 +print total
 +for i in range(0, total):
 +    print list[i]
 +</code>
 +
 +===== 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 <code python>nuke.message("hello") # alert box
 +nuke.tprint("it prints in terminal where nuke launched from")
 +</code>
 +  * get selected node <code python>nuke.selectedNodes() # return a list
 +nuke.toNode('NodeName') # get node with the name
 +</code>
 +  * get format and node format <code python>
 +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*'-'
 +</code>
 +  * get select node knobs (cool way for GUI programming of existing node) <code python>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)
 +</code>
 +  * get active knob from right click on knob <code python>
 +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)
 +</code> \\ {{:appwiki:nuke:nuke_script_get_knob.jpg|}} {{:appwiki:nuke:nuke_script_get_knob_2.jpg|}}
 +  * get or set gui value <code python>print znode.knob ('knobName').value()
 +print znode['knobName'].value()
 +znode.knob (i).setValue('theValue')</code>
 +
 +  * write to file and read from file <code python>
 +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()
 +</code>
 +  * deal with 2D position animation curve (pre-baked curve required) <code python>
 +# 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
 +</code>
 +  * node creation related<code python>
 +# 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
 +
 +</code>
 +  * node attributes related<code python>
 +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)
 +</code>
 +
 +  * animation related <code python>
 +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")
 +</code>
 +  * plugins <code python>nuke.pluginPath() # list all plugin path, use first found in path
 +nuke.pluginAddPath(os.path.abspath("/my/path")) # all os compatile
 +</code>
 +===== 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<code python>
 +import sys; sys.path.insert(0, "/myPythonScriptDir/dev/")
 +import MyPythonFileNameOnly as myFirstGUI
 +m = menubar.addMenu("MyCustMenu")
 +m.addCommand("Menu Item Name", "myFirstGUI.go()")
 +</code>
 +    * menu.py can also be used to change/add menu shortcut ([[http://docs.thefoundry.co.uk/nuke/63/pythondevguide/custom_ui.html#assigning-a-hotkey|read reference]])
 +    * menu.py can also be used to set node default setting ([[http://docs.thefoundry.co.uk/nuke/63/pythondevguide/custom_ui.html#knobdefaults-ref-label|read reference]])
 +  - sample code of Python GUI tool for menu integration<code python>
 +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()
 +</code>
 +
 +===== Python-Panel GUI design=====
 +
 +  * ref here: 
 +    * build guide: http://docs.thefoundry.co.uk/nuke/63/pythondevguide/custom_panels.html#python-panels
 +    * knob type: http://docs.thefoundry.co.uk/nuke/63/ndkdevguide/knobs-and-handles/knobtypes.html
 +    * custom panel guide: http://docs.thefoundry.co.uk/nuke/63/pythondevguide/custom_panels.html
 +
 +
 +  * common GUI element <code python>
 +p = nuke.Panel('My Pop-up Panel')
 +p.addButton("cool")
 +result = p.show()
 +</code>
 +  * built-in GUI panel_test<code python>from nukescripts import panel_test
 +panel_test.panel_example()
 +</code>
 +
 +  * tab window template <code python>
 +
 +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()
 +</code>
 +  * GUI knob button with multi-line pop-up message <code python>
 +self.addKnob(nuke.PyScript_Knob("HelpBtn", "Tip*Trick", "nuke.message(\"\\n1.ask me line 1.\\n2.check my update line2.\")"))
 +</code>
 +===== My Nuke Python Script tools =====
 +
 +Example of procedure GUI design
 +  * tracker in full resolution image into crop reformat image <code python>
 +#============================
 +# 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)    
 +</code>
 +
 +Example of Class like GUI design
 +  * copy BoundBox to CornerPin setting<code python>
 +#============================
 +# 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()
 +</code>
 +  * roto shape point access and control script <code python>
 +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)) 
 +</code>