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:// | ||
+ | |||
+ | | action | shortcut, cmd=ctrl | | ||
+ | | open node property | double-click, | ||
+ | | open node property float | cmd+double-click, | ||
+ | | close all property | alt+click on x on panel | | ||
+ | ====== Nuke Intro ====== | ||
+ | |||
+ | ===== Tracking in Nuke ===== | ||
+ | |||
+ | * tracker node: | ||
+ | * 2D for translation, | ||
+ | * require: 1 point for translation, | ||
+ | * planar tracker node: | ||
+ | * 2.5D for translation, | ||
+ | * 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 " | ||
+ | * 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", | ||
+ | |||
+ | **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 | ||
+ | </ | ||
+ | |||
+ | **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] | ||
+ | </ | ||
+ | |||
+ | ===== Interact with Nuke GUI interface ===== | ||
+ | |||
+ | ref: http:// | ||
+ | |||
+ | ** 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.tprint(" | ||
+ | </ | ||
+ | * get selected node <code python> | ||
+ | nuke.toNode(' | ||
+ | </ | ||
+ | * 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*' | ||
+ | </ | ||
+ | * get select node knobs (cool way for GUI programming of existing node) <code python> | ||
+ | znode=znodes[0] | ||
+ | for i in range(znode.getNumKnobs()): | ||
+ | print '" | ||
+ | |||
+ | # method 2 | ||
+ | help(nuke.selectedNode()) #list all node method | ||
+ | |||
+ | nuke.selectedNode().Class() #print node class name | ||
+ | |||
+ | # qwidget under mouse | ||
+ | from PySide import QtGui, | ||
+ | def getPos(): | ||
+ | pos = QtGui.QCursor.pos() | ||
+ | widget = QtGui.qApp.widgetAt(pos) | ||
+ | print(widget) | ||
+ | QtCore.QTimer.singleShot(5000, | ||
+ | |||
+ | # 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 <code python> | ||
+ | knobMenu = nuke.menu(" | ||
+ | knobMenu.addCommand(' | ||
+ | |||
+ | topMenu = nuke.menu(' | ||
+ | topMenu.addCommand(' | ||
+ | |||
+ | 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, | ||
+ | </ | ||
+ | * get or set gui value <code python> | ||
+ | print znode[' | ||
+ | znode.knob (i).setValue(' | ||
+ | |||
+ | * write to file and read from file <code python> | ||
+ | import sys | ||
+ | import os | ||
+ | filename='/ | ||
+ | fp = open(filename, | ||
+ | fp.write( "0 0 0\n" ) | ||
+ | trackSrcX = znode.knob(' | ||
+ | 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(' | ||
+ | trackDst.clearAnimated(0) | ||
+ | trackDst.clearAnimated(1) | ||
+ | trackDst.setAnimated(0) | ||
+ | trackDst.setAnimated(1) | ||
+ | |||
+ | trackX = trackDst.animation(0) | ||
+ | trackY = trackDst.animation(1) | ||
+ | fp = open(filename, | ||
+ | for line in fp: | ||
+ | if line.startswith(' | ||
+ | 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) <code python> | ||
+ | # like znode as cornerPin node | ||
+ | # read curve | ||
+ | trackSrc = znode.knob(' | ||
+ | if not trackSrc.isAnimated(0) or not trackSrc.isAnimated(1) : | ||
+ | nuke.message(' | ||
+ | trackSrcX = trackSrc.animation(0) | ||
+ | trackSrcY = trackSrc.animation(1) | ||
+ | |||
+ | # write curve | ||
+ | </ | ||
+ | * node creation related< | ||
+ | # method 1 | ||
+ | newNode=nuke.nodes.CornerPin2D(name=' | ||
+ | # method 2 | ||
+ | nuke.createNode(' | ||
+ | |||
+ | # 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=" | ||
+ | crop=" | ||
+ | |||
+ | newName=fullTracker+" | ||
+ | newNode=nuke.nodes.Tracker3(name=newName) | ||
+ | | ||
+ | newNode[' | ||
+ | newNode[' | ||
+ | newNode[' | ||
+ | newNode[' | ||
+ | newNode[' | ||
+ | newNode[' | ||
+ | newNode[' | ||
+ | newNode[' | ||
+ | newNode[' | ||
+ | newNode[' | ||
+ | newNode[' | ||
+ | newNode[' | ||
+ | </ | ||
+ | |||
+ | * animation related <code python> | ||
+ | curNodeAttr = nuke.toNode(" | ||
+ | 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, | ||
+ | # check value expression | ||
+ | curNodeAttr.hasExpression() # 1,0 | ||
+ | curAnimCurve.noExpression() # 1,0 | ||
+ | # set expression connection | ||
+ | animCurveB.setExpression(' | ||
+ | # get expression | ||
+ | exp = curAnimCurve.expression() | ||
+ | # get key | ||
+ | keys = curAnimCurve.keys() | ||
+ | curAnimCurve.addKey(keys) | ||
+ | curAnimCurve.clear() | ||
+ | # same as | ||
+ | nuke.animation(" | ||
+ | </ | ||
+ | * plugins <code python> | ||
+ | nuke.pluginAddPath(os.path.abspath("/ | ||
+ | </ | ||
+ | ===== menu.py ===== | ||
+ | |||
+ | Nuke menu customization | ||
+ | - put menu.py in " | ||
+ | - sample code of import a py file GUI tool in menu.py file< | ||
+ | import sys; sys.path.insert(0, | ||
+ | import MyPythonFileNameOnly as myFirstGUI | ||
+ | m = menubar.addMenu(" | ||
+ | m.addCommand(" | ||
+ | </ | ||
+ | * menu.py can also be used to change/add menu shortcut ([[http:// | ||
+ | * menu.py can also be used to set node default setting ([[http:// | ||
+ | - sample code of Python GUI tool for menu integration< | ||
+ | import nuke | ||
+ | import nukescripts | ||
+ | |||
+ | class myFirstGUI(nukescripts.panels.PythonPanel): | ||
+ | | ||
+ | def __init__(self, | ||
+ | nukescripts.panels.PythonPanel.__init__(self, | ||
+ | # gui preset | ||
+ | newline = nuke.Text_Knob("" | ||
+ | newline.setVisible(False) | ||
+ | |||
+ | self.btn01=nuke.PyScript_Knob(" | ||
+ | self.addKnob(self.btn01) | ||
+ | |||
+ | self.addKnob(newline) | ||
+ | self.addKnob(nuke.PyScript_Knob(" | ||
+ | def knobChanged( self, knob ): | ||
+ | if knob == self.btn01: | ||
+ | print(" | ||
+ | |||
+ | def go(): | ||
+ | mypanel = myFirstGUI(" | ||
+ | mypanel.show() | ||
+ | </ | ||
+ | |||
+ | ===== Python-Panel GUI design===== | ||
+ | |||
+ | * ref here: | ||
+ | * build guide: http:// | ||
+ | * knob type: http:// | ||
+ | * custom panel guide: http:// | ||
+ | |||
+ | |||
+ | * common GUI element <code python> | ||
+ | p = nuke.Panel(' | ||
+ | p.addButton(" | ||
+ | result = p.show() | ||
+ | </ | ||
+ | * built-in GUI panel_test< | ||
+ | panel_test.panel_example() | ||
+ | </ | ||
+ | |||
+ | * tab window template <code python> | ||
+ | |||
+ | class modelPanel(nukescripts.panels.PythonPanel): | ||
+ | | ||
+ | def __init__(self, | ||
+ | nukescripts.panels.PythonPanel.__init__(self, | ||
+ | # | ||
+ | self.addKnob(nuke.Text_Knob(" | ||
+ | |||
+ | newline = nuke.Text_Knob("" | ||
+ | newline.setVisible(False) | ||
+ | | ||
+ | self.addKnob(nuke.PyScript_Knob(" | ||
+ | self.addKnob(newline) | ||
+ | self.addKnob(nuke.PyScript_Knob(" | ||
+ | self.addKnob(newline) | ||
+ | |||
+ | # | ||
+ | self.addKnob(nuke.Text_Knob(" | ||
+ | self.addKnob(nuke.PyScript_Knob(" | ||
+ | self.addKnob(newline) | ||
+ | # | ||
+ | self.addKnob(nuke.Text_Knob(" | ||
+ | self.addKnob(nuke.PyScript_Knob(" | ||
+ | self.addKnob(newline) | ||
+ | |||
+ | |||
+ | #========== show up script run seperately | ||
+ | panel = None | ||
+ | global panel | ||
+ | if not panel: | ||
+ | panel = modelPanel(" | ||
+ | panel.show() | ||
+ | </ | ||
+ | * GUI knob button with multi-line pop-up message <code python> | ||
+ | self.addKnob(nuke.PyScript_Knob(" | ||
+ | </ | ||
+ | ===== 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(' | ||
+ | p.addSingleLineInput(' | ||
+ | p.addSingleLineInput(' | ||
+ | p.addButton(' | ||
+ | p.addButton(' | ||
+ | |||
+ | ret = p.show() | ||
+ | |||
+ | fullTracker = p.value(' | ||
+ | crop = p.value(' | ||
+ | |||
+ | if ret: | ||
+ | print fullTracker, | ||
+ | newName=fullTracker+" | ||
+ | newNode=nuke.nodes.Tracker3(name=newName) | ||
+ | print newName+" | ||
+ | newNode[' | ||
+ | newNode[' | ||
+ | newNode[' | ||
+ | newNode[' | ||
+ | newNode[' | ||
+ | newNode[' | ||
+ | newNode[' | ||
+ | newNode[' | ||
+ | newNode[' | ||
+ | newNode[' | ||
+ | newNode[' | ||
+ | newNode[' | ||
+ | </ | ||
+ | |||
+ | 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, | ||
+ | nukescripts.panels.PythonPanel.__init__(self, | ||
+ | # gui preset | ||
+ | newline = nuke.Text_Knob("" | ||
+ | newline.setVisible(False) | ||
+ | self.btn01=nuke.PyScript_Knob(" | ||
+ | # | ||
+ | self.addKnob(self.btn01) | ||
+ | self.btn02=nuke.PyScript_Knob(" | ||
+ | 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, | ||
+ | if knob == self.btn02: | ||
+ | global p1x | ||
+ | global p1y | ||
+ | global p2x | ||
+ | global p2y | ||
+ | global p3x | ||
+ | global p3y | ||
+ | global p4x | ||
+ | global p4y | ||
+ | znode = nuke.selectedNode() | ||
+ | znode[" | ||
+ | znode[" | ||
+ | znode[" | ||
+ | znode[" | ||
+ | znode[" | ||
+ | znode[" | ||
+ | znode[" | ||
+ | znode[" | ||
+ | znode[" | ||
+ | znode[" | ||
+ | znode[" | ||
+ | znode[" | ||
+ | znode[" | ||
+ | znode[" | ||
+ | znode[" | ||
+ | znode[" | ||
+ | |||
+ | bppanel = bboxPinPanel(" | ||
+ | bppanel.show() | ||
+ | </ | ||
+ | * roto shape point access and control script <code python> | ||
+ | node = nuke.selectedNode() | ||
+ | knob = node[' | ||
+ | for element in knob.rootLayer: | ||
+ | for index, point in enumerate(element): | ||
+ | print index, point.center.getPosition(nuke.frame()) | ||
+ | # setPosition(CVec2(cpx, | ||
+ | </ | ||