Nuke Python 入门

本章的例子帮你初步了解Nuke Python API的使用。

脚本大小写敏感,需要输入正确才能运行。拷贝时注意缩进,如报错请自己更正。

创建节点设置节点控制

此部分演示如何创建节点,设置节点控制

在用户界面创建节点

在用户界面创建类似 menu toolbar的响应节点,使用下面语法:

nuke.createNode( "nodename" )

nodename 就是你要创建节点的名字.

这句话在用户界面创建一个新的节点,会在节点图中挂接到用户选择的节点上,并打开节点的属性面板。另外,新节点上默认的knob也设置了。
想创建blur节点,用这句话,输入:

nuke.createNode("Blur")
创建脚本节点

为脚本,批渲染,某些后台程序使用而创建的节点,请使用下面的语法:

nuke.nodes.nodename(...)

其中nodename是节点的名字。
这创建一个新的node对象。在节点图中没有和其他节点相连,也没打开节点的属性面板,也不会设置默认knob。
例如,添加一个Blur节点,请输入:

nuke.nodes.Blur()

和其他节点连接:

nuke.nodes.Blur().setInput( 0, nuke.selectedNode() )
创建时添加控制

创建节点时添加必要的控制属性,语法如下:

nuke.nodes.node( control = value )

例子:

nuke.nodes.Blur( size = 10 )

创建一个节点,并重命名:

nuke.nodes.nodename( name="newname")

创建一个名为Projection_Cam的摄像机:

nuke.nodes.Camera( name="Projection_Cam" )

创建指向文件的读取节点:

nuke.nodes.Read( file = " filePath/filename.txt" )

赋值

既然在创建节点后想操纵它,那给其赋值就合情理。可以用变量来引用节点。
添加一个节点,并赋值给变量:

variable = nuke.nodes.nodename()
b = nuke.nodes.Blur()
b["size"].setValue( 10)

获取已存在节点

有时候需要读取节点图中已经有的节点。
通过名字去读节点:

nuke.toNode("dagnodename")

如果节点图里面有个叫 Blur1 的节点,使用下面的语句来读取:

myblurNode = nuke.toNode('Blur1')

获取选中的节点

获取当前选择的节点:

selectNode = nuke.selectedNode()

如果选了多个节点,nuke返回最底部的节点。想读取所有的节点,请使用返回选择的列表:

selectNodes = nuke.selectNodes()

添加控制

现在我们看看如何给已经存在的节点设置属性。如果你想添加一个新的控制呢? 你要使用下面的句子:

b = nuke.nodes.nodename(...)
k = nuke.Array_Knob( "name", "label")
b.addKnob(k)

假设你输入了下面语句:

b = nuke.nodes.Blur()
k = nuke.Array_Knob("myctrl", "My Control" )
b.addKnob(k)
image
image

如果你想创建滑动控制,而不是输入框,请用下面的句子( 把Array_Knob替换成 WH_Knob)

b = nuke.nodes.Blur()
k = nuke.WH_Knob("myctrl", "My Control" )
b.addKnob(k)

下面的句子,会添加一个checkbox:

b = nuke.nodes.Blur()
k = nuke.Boolean_Knob("myctrl", "My Control" )
b.addKnob(k)

现在有了控制,但没有提示,咱添一个,给tool tip添加提示 My tooltip:

k.setTooltip('My tooltip' )
image
image

隐藏、展示节点的属性panel

使用showControlPanel() hideControlPanel()函数来设置一个节点的属性面板的打开与关闭。例如,展示新节点Blur的属性面板:

n = nuke.toNode("Blur1")
n.showControlPanel()

默认情况下,当在用户界面nuke.createNode(...)创建节点,属性面板是打开的。不想属性面板在创建时打开,请给createNode()传入inPanel,并设置为false。

nuke.createNode( "Blur", inPanel = False )

连接节点,设置输入

可以用脚本来设置节点的输入。假设你想添加Read和Merge节点( 这个例子,是over节点)并将Read节点连接到over节点的A和B输入(数字1和0).

image
image

添加Read节点和over节点,并说明over节点输入的使用,例如,下面的语句:

r1 = nuke.nodes.Read( file="filepath/filename.ext" )
r2 = nuke.nodes.Read( file ="filePaht/filename.ext")
m = nuke.nodes.Merge( inputs=[r2, r1] )

设置控制的默认值

可以给属于同一个类的节点设置控制的默认值。当默认值设置后,所有名字相同的控制都会是这个值。

nuke.knobDefault()

例如,想设置所有Blur节点的size 控制为20:

nuke.knobDefault( "Blur.size", "20" )

把项目设置中frame范围的最后frame设置为200:

nuke.knobDefault( "Root.last_frame", "200" )

注意,节点类的首字母必须大写。
knobDefault也可以设置 file-format-specific控制。但文件名变化时,这些控制被加入了 Read, Write, 其他file-format-独立节点。说明file-format-specific默认值,使用class名字,后跟文件扩展名 和 控制名字,请有.来区分,例如:

nuke.knobDefault( "Read.exr.compression", "2")
nuke.knobDefault( "Read.exr.disable_mmap", "True")

渲染时用Write节点

用脚本添加了Write节点,现在要渲染1-35帧。
渲染一个单独的节点:

nuke.execute(" name", start, end, incr )

在我们的例子里:

nuke.execute(" Write1", 1, 35, 2) or nuke.execute("Write1, start=1, end=35,incr=2)

也可以使用

nuke.render( name, start, end, incr )

渲染多个Write 节点和范围,请输入:

nuke.executeMultiple( (variable,), ([start, end, incr], ) ) varible--Write nodes

外部程序序列化

FrameCycler是nuke给flipbooking的默认程序,你也可以用别的程序。像这样就得用python写。例子就是基于RV来实现,位于pyQtExample目录下面,如下操作:
1. 找到filpbookingExample.py 文件,根据自己配置修改环境变量
2. 将其保存到你的 .nuke目录,命名为 myflipbook.py
3. 在自己的 init.py( or menu.py )文件中,添加:

from myflipbook import *

更多信息请查看python文档

列举节点的控制

如果需要nuke可以列出节点所有的控制,操作如下:

for i in range( getNumKnobs() ):
            print knob(i).name()

列出Blur节点的控制,前面创建的并赋值给了b:

for i in range( b.getNumKnobs() ):
            print b.knob(i).name

undo和redo

nuke.undo  nuke.redo

帧导航

使用活动窗口的 frame navigation按钮,输入命令:

nuke.activeViewer().frameControl(i)
其中i是一个整型,表示了想要执行的导航按钮,可以用下面的值替换:
  • -6 to go to the first frame.
  • -5 to play the sequence backward.
  • -4 to go to the previous keyframe.
  • -3 to step back by increment.
  • -2 to go back to the previous keyframe or increment, whichever is * closer.
  • -1 to step back one frame.
  • 0 to stop playback.
  • +1 to step forward one frame.
  • +2 to go to the next keyframe or increment, whichever is closer.
  • +3 to step forward by increment.
  • +4 to go to the next keyframe.
  • +5 to play the sequence forward.
  • +6 to go to the last frame.
    也可以将其赋值给快捷键。例如,将 播放 按钮连接到 向上箭头:
  1. 在你的插件目录 创建 menu.py ,
  2. 添加如下代码:
def play():
    v = nuke.activeViewer()
    if v:
        v.play( 1 )
menubar = nuke.menu("Nuke")
m = menubar.addMenu("&File")
m.addCommand("@;Play", "play()", "Up")

设置帧范围

设置单个的帧范围:

nuke.FrameRange()

只能设置一种

frange = nuke.FrameRange(" 1-100 x 2")

要迭代上面range的frame,使用:

for f in frange:
        print f

也可以使用下面方法:

frange.setFirst( int )
frange.setLast( int )
frange.setIncrement( int )
frange.first()
frange.last()
frange.increment()
frange.frames()
frange.getFrame( int )
frange.isInRange( int )
frange.minFrame()
frange.maxFrame()
frange.stepFrame()

存储多个帧范围:

nuke.FrameRanges()

当使用这个函数时,可以按下面方式定义帧范围:

  • 列出所有帧
frange = nuke.FrameRange( [1, 2, 3,6, 7])
  • 使用一个字符串
franges = nuke.FrameRanges( "1-100 2-300X2" )
  • 使用多个字符串
franges = nuke.FrameRanges( ["1-10X1", "15-18X1 30-40X2" ] )
  • 使用多个nuke.FrameRange() :
franges = nuke.FrameRanges( [nuke.FrameRange(1, 100, 5), nuke.FrameRange(200, 250,30] )

迭代遍历所有帧ranges(这个例子中,使用franges变量):

for r in franges:
    for f in r:
        print f

也可以使用下面的函数:

franges.size()
franges.add()
franges.minFrame()
franges.maxFrame()
franges.clear()
franges.toFrameList()
franges.getRange()
franges.compact()

优化frame range表达的方式。其会移除复制的frame ranges,用更紧凑的方式表达,下面有两个例子:

franges1 = nuke.FrameRanges("10-7x-1 1-5x1 3-7x1)
franges1.compact()
print "Ranges1: " +franges

返回 Ranges1: 1-10x1
例子2:

franges2 = nuke.FrameRanges(" 10-7x-1 6-8x1 1-4x1 2-3x1")
franges2.compact()
print "Ranges2: " + franges2

返回: Ranges2: 1-4x1 6-10x1

文件名中标注帧号

nuke中,文件名里可以通过#或者表达式 %04d 来表示帧。这你就会发现 nukescripts.replaceHashes()好用。这让帧号码替换极为容易:

filename = nukescripts.replaceHashes( node['file'].value() ) % nuke.frame()

节点间拷贝动画曲线

动画曲线从 Blur1 拷贝到 Blur2:

b1= nuke.nodes.Blur()
b2= nuke.nodes.Blur()
k1 = b1['size']
k1.setAnimated()
k1.setValue( 10, time=30)
k1.setValue( 20, time=40)
k2=b2['size']
k2.copyAnimations( k1.animations() )

重载某节点的创建

例如,nuke包含两种merge节点: Merge Merge2. 默认Merge2是从工具栏上选择才能使用的。如果你更喜欢Merge,就可以重载创建,让其成为默认创建类型。按下面步骤:

  • 创建menu.py
  • 添加如下代码
class MyCustomNodes():
    def __getattr__(self, args):
        if args == "Merge2" : args = "Merge"
            return nuke.NodeConstructor(args)
nuke.nodes = MyCustomNodes()

用nuke.createNode也能完成同样的功能,那么就用下面的代码:

def createMyCustomNodes( node, knobs="", inpanel = True):
            if node =="Merge2" : node = "Merge"
            return nukeOriginalCreateNode( node=node, knobs=knobs, inpanel = inpanel)
nuke.createNode = createMyCustomNodes

获取正在运行的Nuke环境信息

nuke模块中,有个env对象,给出了nuke运行的环境变量。读取方式:

nuke.env["key"]
nuke.env["PluginExtension"]
NukeVersionMajor
NukeVersionMinor
NukeVersionRelease
NukeversionPhase
NukeVersionPhaseNumber
NukeVersionDate
NukeVersionString
threads
numCPUs
gui
ExecutablePath
ple
WIN32
MACOS
LINUX
64bit

打印环境变量: nuke.env

获取节点的Metadata

获取节点的元数据,并存在字典里:

nuke.toNode("Read1").metadata()

某一帧或者视口的元数据:

nuke.toNode("Read1").metadata("key", frame, "view" )

已经在一个节点里加载了双目数据,想找出左眼93帧的修改时间:

nuke.toNode("Read1").metadata("input/mtime", 93, "left")

相似,获取右眼95帧文件大小

nuke.toNode("Read1").metadata("input/filesize", 95, "right”)

获取指定元数据:

nuke.toNode("Read1").metadata("key")

例如:

nuke.toNode("Read1").metadata("input/ctime")

创建Dialog和Panel

创建带有ok和cancel按钮的对话框,请按照如下步骤:

  1. 在plug-in文件夹创建menu.py 文件(如果没有此文件的话)。
  2. 在文件中扩展python类 PythonPanel:
class ClassName( nukescripts.PythonPanel ):
        def __init__(self):
            nukescripts.PythonPanel.__init__( self, "titile", "ID" )
  1. 使用addKnob()对对话框添加控制。removeKnob()可以移除控制,knobs()返回控制列表。
writeKnobs() readKnobs()
  1. 用showModalDialog()来显示对话框。
创建模态对话框
Python对话框 例子

控制Frame的对话框。

image
image
import nukescripts
if nuke.env["gui"]:
# The following defines a new class called ModalFramePanel.
   class ModalFramePanel( nukescripts.PythonPanel ):
# The following function creates a dialog titled 'Go to Frame' with the optional ID uk.co.thefoundry.FramePanel. It aso adds an integer control called
'frame' to the dialog. This control is set to the value nuke.frame() which is the
current frame on the timeline.
      def __init__( self ):
         nukescripts.PythonPanel.__init__( self, "Go to Frame", "uk.co.thefoundry.FramePanel" )
         self.frame = nuke.Int_Knob( "frame", "Frame:" )
         self.addKnob( self.frame )
         self.frame.setValue( nuke.frame() )
# The next function shows the dialog as a modal dialog. Doing this automatically adds the 'OK' and 'Cancel' buttons to the dialog.
      def showModalDialog( self ):
         result = nukescripts.PythonPanel.showModalDialog( self )
         if result:
            nuke.frame( self.frame.value() )
# The following function is called testModalPanel and tests whether the dialog works.
   def testModalPanel():
      return ModalFramePanel().showModalDialog()
# This last line calls the test function that then displays the dialog.
   testModalPanel()
# If you want to add the dialog to a menu item, you can also do the following:
menubar = nuke.menu("Nuke")
menubar.addCommand("&File/Show My Panel", testModalPanel)
创建非模态对话框
非模态对话框例子

非模式标签可以停靠在窗口里,并被保存下来。创建步骤:

  1. 如果没有menu.py就在plug-in文件夹创建。
  2. 添加如下代码:
class ClassName( nukescripts.PythonPanel ):
        def __init__( self ):
            nukescripts.PythonPanel.__init__( self, "titile", "ID" )
  1. 使用addKnob()添加控制
  2. 编写第二个创建panel的函数。使用addToPanel()将其添加到pane。nuke.thisPane()来显示。
  3. 创建菜单来调用前面的函数。
  4. 如果想要panel和窗口格局一起保存,那就必须使用init.py注册自己的panel,因为此文件的读取要早于格局的保存:
nukescripts.registerPanel( ID, function)

注销:

nukescripts.unregisterPanel( ID, funciton)

例子:从content 菜单 Pane》Frame Panel可以选择此菜单。

import nukescripts
class FramePanel( nukescirtps.PythonPanel ):
    def __init__(self):
        nukescripts.PythonPanel.__init__( self, "Go to frame", "uk.co.thefoundry.FramePanel")
        self.frame = nuke.Int_knob("frame", "Frame:" )
        self.addKnob(self.frame )
        self.frame.setValue( nuke.frame() )
    def knobChanged( self, knob ):
        if knob == self.frame:
            nuke.frame( self.frame.value() )
    def testPanel():
        return FramePanel().addToPane()
menu = nuke.menu("Pane")
menu.addCommand( "Frame Panel", testPanel)
nukescripts.registerPanel( "uk.co.thefoundry.FramePanel", testPanel )

创建进度条dialog

import threading
import time
def selfDestruct():
    task = nuke.ProgressTask("self destructing" )
    task.setMessage( "deleting files")
    for i in xrange( 0, 100):
        if task.isChanged():
            nuke.executeInMainThread( nuke.message, args= ("Phew!") )
            break
        task.setProgress(i)
        time.sleep( 0.5 )
threading.Thread(None, selfdestruct ).start()

注意:
需要循环,因为不知道何时任务会被取消
不能再nuke的主线程里面运行循环,那会阻塞nuke直到进程结束。
因此,需要开始新线程来控制进度条不能在线程里面调用nuke.message,因此要用nuke.executeInMainThread()来显示消息。

清空当前Nuke(.nk)脚本

nuke.scriptClear()

给立体项目创建View

nuke.Root().addView(" name" )

添加左目:

nuke.Root().addView(" left" )

调整立体项目中的控制值

项目中有left right 的view

n = nuke.nodes.Blur()
n['size'].splitView()
n['size'].setValue( 10, view = "left" )
n['size'].setValue( 20, view = "right")

添加了blur节点,将size的控制分开,左边10,右边20


本节感谢以下朋友的指正:
QQ:

  • 成都-TD-德贵
  • 福州-合成-邵冰
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容

  • 使用下文描述的nuke.add...()函数,当有变量事件(比如,创建节点,加载脚本)时就自动调用python函数...
    N景波阅读 2,638评论 0 1
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,497评论 18 139
  • 不会拍照的厨子不是好的程序猿 可乐鸡翅 配料 : 鸡翅5只 可口可乐1碗 盐 少许 ...
    流浪孩阅读 303评论 2 3
  • 投资谨记三点: 1.把钱放在安全的地方 2.放在哪里鹅下金蛋最多 3.操作起来简单明了 我们集中精力去做的事情会在...
    万夏伊阅读 127评论 0 0