graphic:python:nuke

To Merge here: App Nuke

Technique Section

  • Method 1: nuke environment setting, use that to let nuke load its init.py and menu.py there
    NUKE_PATH
    D:/myPath_for_nuke
  • Method 2: edit ~/.nuke/init.py, and menu.py, to load your custom init.py and menu.py at other location
    import nuke
    nuke.pluginAddPath('D:/myPath_for_nuke')
  • system detection
    import sys
    osMode = 'other'
    if sys.platform in ['win32','win64']:
        osMode = 'win'
    elif sys.platform == 'darwin':
        osMode = 'mac'
    elif sys.platform == 'linux2':
        osMode = 'linux'
    print("OS: {0}".format(osMode))
  • nuke detect GUI mode
    import nuke
    nuke.env['gui'] # print 1 or 0
  • nuke will auto run all the init.py in the path directories before launch
    init.py
    import sys
    if nuke.NUKE_VERSION_STRING.startswith('9'):
        nuke.pluginAddPath('./9.0') # relative path
        sys.path.append('D:/myOtherPythonModulePath') # abs path
  • launch nuke with custom python initial script
    Nuke.exe replaceWritePaths.py other_args
  • menu.py file is another place for you to put menu related script, it is like init.py but more for menu creation
    # nuke main menu object
    nuke.menu('Nuke').addCommand('subMenuFolder/menuItemName','print("your python cmd example")', icon='/iconPath/toolName.png')
     
    # nuke gizmo menu object
    cur_menu = nuke.menu("Nodes").addMenu("myGiz", icon="myGizmo.png")
    cur_menu.addCommand('subMenuFolder/menuItemName','print("your python cmd example")', icon='/iconPath/toolName.png')
     
    # custom image formats
    nuke.addFormat("1280 768 0 0 1280 768 1 HD 1280 Square")
  • the event driven functions that nuke will execute when the event happend. You can put those event function in init.py file, which nuke reads after launch. (in both gui and cmd mode)
  • nuke before render event example
    nuke.addBeforeRender(funcNameToDoBeforeRender) # it pass the write node as nuke.thisNode
  • render the all write node in script
    "C:\pathToNuke\NukeVersion.exe" -nukex -i -F 1001-1020 -x "R:/pathToScript/myNukeScript.nk"
  • render the Defined Write Node
    "C:\pathToNuke\NukeVersion.exe" -nukex -i -X ThatFinalWrite "R:/pathToScript/myNukeScript.nk" 1001-1020
  • menu creation with one-line and auto creation if not exist
    # it automatically create xTool menu in menubar, 
    # and create "CompHelper" menu item that call function string, with shortcut and icon 
    import sys,os;myPath=r'D:\Dev\CompHelper'
    myPath in sys.path or sys.path.append(myPath);import CompHelper;
    cmd = nuke.menu('Nuke').addCommand("xTool/CompHelper", 'CompHelper.main()',icon=os.path.join(myPath,'icons','CompHelper.png'))
    cmd.setIcon(os.path.join(myPath,'icons','CompHelper.png'))
  • save script
    nuke.scriptSave( outScript )
     
    curScript = nuke.toNode("root").name()
    nuke.scriptSaveAs("/scratch/snapshot.nk")
    nuke.scriptSaveAs(curScript)
  • set knob to readonly/locked
    knob.setEnabled(False)
     
    # lock with a flag
    nuke.selectedNode()[knob].setFlag(nuke.DISABLED) 
    nuke.selectedNode()[knob].clearFlag(nuke.DISABLED)

common menu operation codes

# top menu and side bar menu obj
nuke.menu("Nuke")
nuke.toolbar("Nodes")
 
# add menu and add cmd obj
menubar = nuke.menu("Nuke") # main menu bar
my_menu = menubar.addMenu("MyMenu") # menu object
my_menu.addCommand("Test","print('Test')") # menu item; subFolder/Test for subfolder cmds
 
menubar.addMenu("MyMenu") # Important, without a var to hold it, it becomes menuItem object instead of menu obj
 
# get items of a ui object
# list direct child UI object
menubar.items()
# return menu child with that name
menubar.menu('MyMenu')
# return menu or menuItem child w that name
menubar.findItem('MyMenu')
# loop method of listing
name_item_child_list = [ [cur_item.name(), cur_item] for cur_item in menubar.items() ]
print(name_item_child_list )
  • root first frame and last frame
    start = int(nuke.Root().knob('first_frame').value())
    end = int(nuke.Root().knob('last_frame').value())
  • get and goto frame
    curFrame = nuke.frame() # get
    nuke.frame(1002) # goto
  • Common maya like file operation, like Import/Edit file, and export selected/ save file as.
    # import file to viewport
    nuke.nodePaste(in_filepath.replace('\\', '/'))
    # edit File
    nuke.scriptOpen(in_filepath.replace('\\', '/'))
    # save Selected as File
    nuke.nodeCopy(out_filepath)
    # save file as
    nuke.scriptSaveAs(out_filepath)
  • get current script file path
    full_path = ''
    try:
        full_path = nuke.scriptName()
    except:
        nuke.message('No path found.')
  • set a nuke node default
    nuke.knobDefault( 'Write.afterRender', 'import myFun;myFun.some_action()')
  • nuke script's root root
    root = nuke.thisNode()
  • nuke callBack function to access current call node
    thisNode = nuke.thisNode()
  • read
    my_node = nuke.createNode('Read')
    my_node['file'].fromUserText('/path/to/your/file.mov')
  • get selected nodes with type filtering
    selected = [x for x in nuke.selectedNodes() if x.Class() == 'Read']
  • find all read nodes
    nuke_readNodes = [x for x in nuke.allNodes(recurseGroups=True) if x.Class() == 'Read']
    self.memoData['nuke_path_list'] = [os.path.normpath(os.path.dirname(x['file'].value())) for x in nuke_readNodes]
  • find all write nodes
    def getNodeByClass(nodeClass, startNode):
        if startNode.Class() == nodeClass:
            yield startNode
        elif isinstance(startNode, nuke.Group):
            for child in startNode.nodes():
                for foundNode in RecursiveFindNodes(nodeClass, child):
                    yield foundNode
    allWriteNodes = [w for w in getNodeByClass('Write', nuke.root())]
  • render write node
    # set after render python script
    cur_node.knob('afterRender').setValue("WriteToMov()") # call a python function after done rendering
    # call render
    nuke.execute( nodeName, firstFrame, lastFrame )

Knob Operation

  • add knob callback
    node.knob('knobChanged')
    nuke.addKnobChanged(function)
    nuke.removeKnobChanged(function)

Nuke Tcl Expression

Replace Single Line String to Multi Line Display

  • put noteStr text input value into current message text block value, the single line format as “test / better one / best line” as
    [regsub -all " / " [value noteStr] "\n"]
  • it is useful to put [argv 8] like in the noteStr value, as cmd arg has to be in single line format

Use Express to Link StrValue to IntValue

  • create a user text input knob, then use expression to link int knob to this text knob, and use [argv 7] like cmd arg to drive text value then updating the int value. (since int knob seems can't set as [argv 7] like)

example

# file attribute expression:
[value rdir]/finals/[value shot]/NK_[value shot].%03d.dpx
# get evaluate result
print (nuke.thisNode()["file"].evaluate())

# mix python in tcl
file "\[value nas_root]/\[value project]/\[value seq]/zup_renders/Comp/\[value RenderType]/\[value shot]_[value FileName]_v[python {str(int(nuke.thisNode()['ver'].value())).zfill(3)} ]/\[value shot]_[value FileName]_v[python {str(int(nuke.thisNode()['ver'].value())).zfill(3)} ].####.\[value file_type]" 

# use cmd
 knobChanged "\ncur=nuke.thisNode()\npathA = \[ cur\[each].value() for each in \['nas_root', 'project', 'seq'] ]\npathB = \['zup_renders/Comp', cur\['RenderType'].value() ]\nsegC = cur\['shot'].value()\nif cur\['FileName'].value() !='':\n    segC+='_'+cur\['FileName'].value()\nsegC+='_v'+ str(int(cur\['ver'].value())).zfill(3)\npathD = \[ segC+'.####.'+cur\['file_type'].value() ]\ncur\['file'].setValue( '/'.join( pathA + pathB + \[segC] + pathD ) )\n"
  • TCL and Python Expression that trigger by frame reading error, as a way to detect error frame like corrupted exr, ref: https://forums.cgsociety.org/t/read-node-on-corrupt-frames-workaround/1650526/2
    1. create a user integer knob on Read node
      1. set its value expression (Python)
        nuke.thisNode().error()
      2. or set its value expression (TCL)
        [value error]
    2. or create a user integer knob on Read node downstream connected node and
      1. set its value express (Python)
        nuke.thisNode().input(0).error()
      2. or set its value express (TCL), which take its topnode
        [value [topnode].error ]

  • addition info:
    • Windows > Error Console for error information

Nuke API

  • nuke used library: nuke help/Documentation/html/content/comp_environment/third_party_software/third_party_libraries.html
  • graphic/python/nuke.txt
  • Last modified: 2021/08/22 19:44
  • by ying