https://www.bilibili.com/video/BV1bm4y1R7X1/?spm_id_from=333.788&vd_source=b1de3fe38e887eb40fc55a5485724480
为Nuke添加内置python编辑器
github地址
令脚本编辑器中显示在nuke中进行的操作对应的代码
首先按shift+s进入首选项设置界面,然后再Panels-Script Editor中勾选 echo python commands to output window
显示节点的详细信息(方便找节点属性名字)
首先选中节点,然后按键盘的i键即可弹出一个窗口,在里面可以找到节点的详细信息.
后台执行脚本
首先通过nuke.env[‘ExecutablePath’]得到nuke程序的路径
然后如果是当前python脚本想要调用令一个python脚本的话,就通过’{}/另一个python脚本的名字.py’.format(os.path.dirname(file ))找到要调用的另一个python脚本的路径,或者就直接用绝对路径.
然后创建command命令:command = ‘“{nuke}” -t -x {script} {要传入的额外参数}’
传入的额外参数可以在要调用的python脚本中通过sys.argv[1],sys.argv[2]… 来得到
最后通过subprocess.Popen(command, shell=True)来使用命令行
后台执行脚本的要点就是命令里记得添加-t和-x即可,不添加就是前台调用了
官方入门文档
官方入门文档地址
从这个文档可以快速的了解到如何通过代码创建节点,设置节点属性,窗口的制作等.可以直接看,代码的英文直译很容易就能明白对应的意思.
常用的命令
通过节点类型得到对应节点: nuke.allNodes(‘Read’)
得到选择的节点并设置节点的属性:
select_node = nuke.selectedNode()
select_node[‘file’].setValue()
nuke消息窗口的显示: nuke.message(“消息窗口内容”)
得到当前工程名字:nuke.root().name()
打开项目:nuke.scriptOpen()
得到nuke程序的路径: nuke.env[‘ExecutablePath’]
导入其他nuke文件: nuke.nodePaste()
保存nuke的文件:nuke.scriptSaveAs(prjPath)
保存当前nuke工程:nuke.scriptSave(“”)
清理当前nuke工程:nuke.scriptClear()
得到nuke程序的路径:nuke.env[‘ExecutablePath’]
第一节
初始设置
在这个路径下C:\Users\用户名.nuke,创建gizmos文件夹,python文件夹,init.py文件,menu.py文件。 init.py文件用来为nuke新增插件识别路径(这样就不需要每个文件夹都加一个__init__.py文件了),都统一加到外面这个init.py文件。 menu.py文件用来控制nuke启动时自动加载的功能 其中init.py文件中内容是
1 2 nuke.pluginAddPath ('./gizmos' ) nuke.pluginAddPath ('./python' )
克服因操作平台的不同而导致的.nuke文件夹路径不同的问题
在menu.py文件中输入: 其中platform可以用来得到当前的操作平台
第二节
设置创建节点时的默认值
nuke.knobDefault(‘Tracker4.shutteroffset’,“centered”) # 设置Tracker节点的shutteroffset的默认值为centered nuke.knobDefault(‘Tracker4.label’, “Motion: [value transform]\nRef Frame: [value reference_frame]”) # 设置Tracker节点的label(节点的显示文本)为Motion: [value transform]\nRef Frame: [value reference_frame]也就是 。加入后的前后对比: 变成了 。其中label中框号中的内容是属性值。 在创建节点时当节点类型为Tracker时设置这个节点的reference_frame的值为nuke的时间滑块的frame值。
如何添加自定义菜单:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 import PythonEditorPythonEditor.nuke_menu_setup(nuke_menu=True , node_menu=True , pane_menu=True ) import nukeimport platformimport nukescriptsnuke.knobDefault('Tracker4.shutteroffset' , "centered" ) nuke.knobDefault('Tracker4.label' , "Motion: [value transform]\nRef Frame: [value reference_frame]" ) nuke.addOnUserCreate(lambda : nuke.thisNode()['reference_frame' ].setValue(nuke.frame()), nodeClass='Tracker4' ) utilitiesMenu = nuke.menu('Nuke' ).addMenu('Utilities' ) utilitiesMenu.addCommand('Autocrop' , 'nukescripts.autocrop()' ) myGizmosMenu = nuke.menu('Nodes' .addMenu('myGizmos' ) myGizmosMenu.addCommand('Autocrop' , 'nukescripts.autocrop()' ) nuke.menu('Nodes' ).addCommand("Transform/Tracker" , "nuke.createNode('Tracker4)" ,"ctrl+alt+t" , icon="Tracker.png" , shortcutContext=2 ')
nuke自带的图标路径
可以在图中的路径处找到nuke自带的图标的名字 然后添加menu时icon参数如果想要是nuke自带的图标那么就可以直接填图标的名字加后缀名,nuke会自动找到
第三节
创建节点
nuke.createNode()
创建节点的同时设置属性值(不属于课程,之前自己搜的)
举例:nuke.nodes.Shuffle(inputs=[texO], red=“red”, green=“black”, blue=“black”, alpha=“white”)
为节点创建预设与快捷键
更改节点的属性值
举例,设置选择的节点的’bbox’属性值为’B’:nuke.selectedNode()[‘bbox’].setValue(“B”) 举例,自定义某一节点的属性值: nuke.toNode(‘Merge1’)[‘bbox’].setValue(“B”)
通过for循环批量更改某一类型的节点属性值
设置所有merge2类型节点的属性值:
通过代码得到节点的类型名
print nuke.selectedNode().Class()
第四节
介绍
针对shuffle节点制作一些功能
shuffleShortcuts.py文件
在.nuke\python\shuffleShortcuts文件夹下创建个shuffleShortcuts.py文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 import nukedef createCustomShuffle (in_channel, out_channel, set_channel, rColor, gColor, bColor ): my_shuffle = nuke.createNode("Shuffle" ) my_shuffle['in' ].setValue(in_channel) my_shuffle['out' ].setValue(out_channel) my_shuffle['red' ].setValue(set_channel) my_shuffle['green' ].setValue(set_channel) my_shuffle['blue' ].setValue(set_channel) my_shuffle['alpha' ].setValue(set_channel) my_shuffle['tile_color' ].setValue(int ('%02x%02x%02x%02x' % (rColor * 255 , gColor * 255 , bColor * 255 , 1 ), 16 )) my_shuffle['label' ].setValue("[value red] > [value out]" ) def shuffleRGBchannels (): select_node = nuke.selectedNode() select_node_x_pos = select_node['xpos' ].value() select_node_y_pos = select_node['ypos' ].value() createCustomShuffle('rgba' , 'rgba' , 'red' , 1 , 0 , 0 ) red_shuffle = nuke.selectedNode() createCustomShuffle('rgba' , 'rgba' , 'green' , 0 , 1 , 0 ) green_shuffle = nuke.selectedNode() createCustomShuffle('rgba' , 'rgba' , 'blue' , 0 , 0 , 1 ) blue_shuffle = nuke.selectedNode() red_shuffle.setInput(0 , select_node) red_shuffle['xpos' ].setValue(select_node_x_pos - 150 ) red_shuffle['ypos' ].setValue(select_node_y_pos + 150 ) green_shuffle.setInput(0 , select_node) green_shuffle['xpos' ].setValue(select_node_x_pos) green_shuffle['ypos' ].setValue(select_node_y_pos + 150 ) blue_shuffle.setInput(0 , select_node) blue_shuffle['xpos' ].setValue(select_node_x_pos + 150 ) blue_shuffle['ypos' ].setValue(select_node_y_pos + 150 ) nuke.menu('Nodes' ).addCommand("Channel/Shuffle (Red to All)" , "shuffleShortcuts.createCustomShuffle('rgba', 'rgba', 'red', 1, 0, 0)" , "ctrl+shift+r" , shortcutContext=2 ) nuke.menu('Nodes' ).addCommand("Channel/Shuffle (Green to All)" , "shuffleShortcuts.createCustomShuffle('rgba', 'rgba', 'green', 0, 1, 0)" , "ctrl+shift+g" , shortcutContext=2 ) nuke.menu('Nodes' ).addCommand("Channel/Shuffle (Blue to All)" , "shuffleShortcuts.createCustomShuffle('rgba', 'rgba', 'red', 0, 0, 1)" , "ctrl+shift+b" , shortcutContext=2 ) nuke.menu('Nodes' ).addCommand("Channel/Shuffle (Alpha to All)" , "shuffleShortcuts.createCustomShuffle('rgba', 'rgba', 'red', 1, 1, 1)" , "ctrl+shift+a" , shortcutContext=2 ) nuke.menu('Nodes' ).addCommand("Channel/Shuffle (Alpha to 0)" , "shuffleShortcuts.createCustomShuffle('rgba', 'rgba', 'red', 0, 0, 0)" , shortcutContext=2 ) nuke.menu('Nodes' ).addCommand("Channel/Shuffle (Alpha to 1)" , "shuffleShortcuts.createCustomShuffle('rgba', 'rgba', 'red', 1, 1, 1)" , shortcutContext=2 ) nuke.menu('Nodes' ).addCommand("Channel/Shuffle (Split RGB channels)" , "shuffleShortcuts.shuffleRGBchannels()" , "ctrl+shift+s" , shortcutContext=2 )
然后在menu.py文件中导入这个模块
init.py文件中定义文件夹路径
第五节
得到项目路径
nuke.root()[‘name’].value()
定位字符串的特定值
举例字符串: Checkerboard_Small_v0002.png 输出 Checkerboard_Smal
1 2 3 name_ext = "Checkerboard_Small_v0002.png" name = name_ext[0 :name_ext.find('_v' )] print name
第六节
弹出输入框让用户输入
inputBox = nuke.getInput(“My First Window”, “default text”) 如果点击Cancel按钮,那么inputBox的值为None
在nuke菜单下放置一个让用户输入所选节点label的工具
首先按照课程的文件夹排列,我们的流程就是,在.nuke\python\shuffleShortcuts文件夹下创建一个新的.py工具文件(主要是因为init.py文件定义了这个文件夹为插件加载路径) 然后去menu.py文件中导入这个新的.py工具文件,这样nuke就能够调用.py文件了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import nukedef shortcut_NodeComment (): selected_node = nuke.selectedNode() old_comment = selected_node['label' ].value() input_box = nuke.getInput("Please enter a node label" , old_comment) if not input_box: nuke.message("Node label will remain as " + old_comment) else : selected_node['label' ].setValue(input_box) nuke.menu('Nuke' ).addCommand('Edit/Shortcuts/Add Comment to Node' , 'shortcut_NodeComment.shortcut_NodeComment()' , 'ctrl+alt+c' , shortcutContext=2 )
1 import shortcut_NodeComment
1 nuke.pluginAddPath('./python/shuffleShortcuts' )
(扩展版)在nuke菜单下放置一个让用户输入所选节点label的工具
不仅可以设置内容,也可以设置显示knob属性,也可以设置节点颜色 内嵌的panel写法举例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import nukescripts.panelsclass my_panel (nukescripts.panels.PythonPanel): def __init__ (self ): super (my_panel, self ).__init__('my_panel' ) selected_Node = nuke.selectedNode() old_comment = selected_Node['label' ].value() knob_list = [] for i in selected_Node.knobs(): knob_list.append(i) self .old_comment_slt = nuke.String_Knob("Comment" , "Comment" , old_comment) self .addKnob(self .old_comment_slt) self .knob_list = nuke.Enumeration_Knob("Knob" ,"Knob" , knob_list) self .addKnob(self .knob_list) self .colour_bool = nuke.Boolean_Knob("Change Node Colour?" , "Change Node Colour?" , False ) self .addKnob(self .colour_bool) p = my_panel() p.show()
教程中的panel写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 import nukedef short_NodeCustomizer (): selected_Node = nuke.selectedNode() old_comment = selected_Node['label' ].value() knob_list = [] for i in selected_Node.knobs(): knob_list.append(i) knob_list.sort() knob_list.insert(0 , 'None' ) knob_list_string = " " .join(knob_list) panel = nuke.Panel("Node Customizer" ) panel.addSingleLineInput("Comment" , old_comment) panel.addEnumerationPulldown("Knob" , knob_list_string) panel.addBooleanCheckBox("Change Node Colour?" , False ) if not panel.show(): return comment_input = panel.value("Comment" ) knob_choice = panel.value("Knob" ) node_label = comment_input + "\n" + knob_choice + ": [value " + knob_choice + "]" if comment_input == "" and panel.value("Knob" ) == "None" and not panel.value("Change Node Colour?" ): nuke.message("Please enter a node label" ) return elif knob_choice == "None" : selected_Node['label' ].setValue(comment_input) elif comment_input == "" : selected_Node['label' ].setValue(knob_choice + ": [value " + knob_choice + "]" ) else : selected_Node['label' ].setValue(node_label) if panel.value("Change Node Colour?" ): selected_Node['tile_color' ].setValue(nuke.getColor()) else : return nuke.menu('Nuke' ).addCommand('Utilities/Node Customizer' , 'shortcut_NodeCustomizer.shortcut_NodeCustomizer()' )
第八节
TCL的使用,链接属性
moblur_controller.py
创建NoOp节点配合TCL表达式,使只通过控制NoOp节点的数值,即可控制所有nuke节点网络图中带有对应属性的属性值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 import nukedef moblur_controller (): node_list = [] for n in nuke.allNodes(): if n.knob('motionblur' ) or n.knob('samples' ): node_list.append(n) NoOp = nuke.createNode('NoOp' ) NoOp['name' ].setValue("GLOBAL_MOTIONBLUR_CONTROLLER" ) NoOp['tile_color' ].setValue(255 ) NoOp['note_font' ].setValue("Bold" ) NoOp.addKnob(nuke.Int_Knob('global_motionblur' , "motionblur" )) NoOp.addKnob(nuke.Double_Knob('global_shutter' , "shutter" )) NoOp.addKnob(nuke.Boolean_Knob('global_disable_moblur' , "disable motionblur" )) NoOp['global_motionblur' ].setValue(1 ) NoOp['global_shutter' ].setValue(0.5 ) NoOp['global_disable_moblur' ].setFlag(nuke.STARTLINE) for node in node_list: if node.knob('motionblur' ): node['motionblur' ].setExpression( 'GLOBAL_MOTIONBLUR_CONTROLLER.global_disable_moblur == 0 ? GLOBAL_MOTIONBLUR_CONTROLLER.global_motionblur : 0' ) node['shutter' ].setExpression('GLOBAL_MOTIONBLUR_CONTROLLER.globsl_shutter' ) elif node.knob('samples' ): node['samples' ].setExpression( 'GLOBAL_MOTIONBLUR_CONTROLLER.global_disable_moblur == 0 ? GLOBAL_MOTIONBLUR_CONTROLLER.global_motionblur : 1' ) node['shutter' ].setExpression('GLOBAL_MOTIONBLUR_CONTROLLER.globsl_shutter' ) def deleteExpressions (): for node in node_list: if node.knob('motionblur' ): node['motionblur' ].clearAnimated() node['motionblur' ].setValue(0 ) node['shutter' ].clearAnimated() node['shutter' ].setValue(0.5 ) elif node.knob('samples' ): node['samples' ].clearAnimated() node['samples' ].setValue(1 ) node['shutter' ].clearAnimated() node['shutter' ].setValue(0.5 ) nuke.addOnDestroy(deleteExpressions) nuke.menu('Nuke' ).addCommand('Utilities/Global Motionblur Controller' , 'moblur_controller.moblur_controller()' )
第九节
使用nuke自带的自定义界面工具来扩展节点
在节点的属性界面右键点击 然后就可以在这里自定义界面 其中divider line是分割线 然后UI可以附带代码
addNodes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 node_list = [] for node in nuke.selectedNodes(): node_list.append(node.name()) nuke.thisNode().knob('addMoreNodes' ).setVisible(True ) nuke.thisNode().knob('addNodes' ).setVisible(False ) node_list_cleaned = '\n·' .join(node_list) nuke.thisNode()['txtknob_node_list' ].setValue("·" +node_list_cleaned) def disableNodesInList (): for i in node_list: if nuke.toNode(i).knob('disable' ): nuke.toNode(i).knob('disable' ).setValue(nuke.thisNode().knob('disable' ).value()) else : print "-" + i + "does not have a 'disable' knob Ignoring..." nuke.toNode("NODE_DISABLER" ).knob("knobChanged" ).setValue('disableNodesInList()' )
addMoreNodes
1 2 3 4 5 6 7 8 9 10 for node in nuke.selectedNodes(): if node.name() in node_list: print node.name()+" is already in the list" else : node_list.append(node.name()) node_list_cleaned = '\n·' .join(node_list) nuke.thisNode()['txtknob_node_list' ].setValue("·" +node_list_cleaned)
clearList
1 2 3 4 5 6 node_list = [] nuke.thisNode().knob('addNodes' ).setVisible(True ) nuke.thisNode().knob('addMoreNodes' ).setVisible(False ) nuke.thisNode()['txtknob_node_list' ].setValue("None" )
将通过这种方法自定义的节点保存成gizmo
在.nuke\gizmos文件夹中新建gizmo文件 然后在nuke中选择节点按ctrl+c 然后进入gizmo文件按ctrl+v即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 set cut_paste_input [stack 0 ]version 10.5 v4 push $cut_paste_input NoOp { name NODE_DISABLER knobChanged disableNodesInList() tile_color 0xff label "\[expr \{ \[value disable] == true ? \"Nodes Disabled\" : \"Nodes Enabled\" \}]" selected true xpos -180 ypos -86 addUserKnob {20 User} addUserKnob {26 "" } addUserKnob {22 addNodes l "Add Selected Nodes To List" T "node_list = \[]\nfor node in nuke.selectedNodes():\n node_list.append(node.name())\n\nnuke.thisNode().knob('addMoreNodes').setVisible(True)\nnuke.thisNode().knob('addNodes').setVisible(False)\n\nnode_list_cleaned = '\\n·'.join(node_list)\n\nnuke.thisNode()\['txtknob_node_list'].setValue(\"·\"+node_list_cleaned)\n\ndef disableNodesInList():\n for i in node_list:\n if nuke.toNode(i).knob('disable'):\n nuke.toNode(i).knob('disable').setValue(nuke.thisNode().knob('disable').value())\n else:\n print \"-\" + i + \"does not have a 'disable' knob Ignoring...\"\nnuke.toNode(\"NODE_DISABLER\").knob(\"knobChanged\").setValue('disableNodesInList()')" +STARTLINE} addUserKnob {22 addMoreNodes l "Add More Selected Nodes To List" +HIDDEN T "for node in nuke.selectedNodes():\n if node.name() in node_list:\n print node.name()+\" is already in the list\"\n else:\n node_list.append(node.name())\n\nnode_list_cleaned = '\\n·'.join(node_list)\n\nnuke.thisNode()\['txtknob_node_list'].setValue(\"·\"+node_list_cleaned)\n" +STARTLINE} addUserKnob {26 "" } addUserKnob {22 clearList l "Clear List" T "node_list = \[]\n\nnuke.thisNode().knob('addNodes').setVisible(True)\nnuke.thisNode().knob('addMoreNodes').setVisible(False)\n\nnuke.thisNode()\['txtknob_node_list'].setValue(\"None\")" +STARTLINE} addUserKnob {26 spacer l " " -STARTLINE T " " } addUserKnob {6 disable -STARTLINE} addUserKnob {26 "" } addUserKnob {26 txtknob_node_list l "NODE LIST:" T None } addUserKnob {26 "" } }