Nuke Python 控制通道和层

本节讲如何获取和创建通道和层(也叫通道,集合)。

读取通道

获取当前Nuke工程中所有的通道:

nuke.channels()

# Result:
['rgba.red', 'rgba.green', 'rgba.blue', 'rgba.alpha', 'depth.Z', 'forward.u', 'forward.v', 'backward.u', 'backward.v', 'disparityL.x', 'disparityL.y', 'disparityR.x', 'disparityR.y', 'mask.a', 'rotopaint_mask.a']

获取层名字:

nuke.layers()

# Result:
['rgb', 'rgba', 'alpha', 'depth', 'motion', 'forward', 'backward', 'disparity', 'disparityL', 'disparityR', 'mask', 'rotopaint_mask']

获取选取节点的通道:

node = nuke.selectedNode()
print node.channels()

# Result:
['rgba.red', 'rgba.green', 'rgba.blue', 'rgba.alpha']


添加新通道

添加一个新通道:

nuke.Layer('customLayer', ['red', 'green', 'blue'])

注意: 层不存在时,此函数会创建一个出来


警告: 不要给默认层添加通道,因为Nuke工程不保存。

重命名现有层:

nuke.Layer( 'customLayer' ).setName( 'myLayer' )

警告: 不要重命名默认层,当重新加载工程时会报错。

例子
autoComp

这个例子检查exr文件中的通道,常识讲第二pass合到beauty渲染中。


可以参考脚本the sample exr

首先,写个函数autoComp,接收一个节点作为参数。此节点包含第二通道或者“AOVs"(任意输出值)。第一步先获取节点的通道:

def autoComp( node ):
    channels = node.channels()

node.channels()返回此节点的所有通道,返回值是通道名列表[‘rgba.red’, ‘rgba.green’, ‘rgba.blue’],为了获取层名,
使用点号来切分通道名,并获取结果的第一部分:

layers = [c.split('.')[0] for c in channels]

但是,这留给我们很多层复制名,想去掉这些复制层,先把这些结果放入set,然后在倒回list

layers = list( set([c.split('.')[0] for c in channels]) )

方便起见先排序,代码如下:

def autoComp( node ):
    channels = node.channels()
    layers = list( set([c.split('.')[0] for c in channels]) )
    layers.sort()

准备好了所有层和通道,我们就可以建一个简单UI,在合成中将现有的buffer 对应到正确的pass。创建标题为“Map AVOS”的panel,
并添加三个下拉菜单:

  • texture -- 附加的层包含纹理颜色
  • diffuse -- 附加上的层包含 diffuse 灯光信息
  • specular -- 附加的层包含 specular信息

将我们获取的层名填入下拉菜单。 此例中,值为TCL样式的列表,空格区分(和‘ ’.join()很像):

p = nuke.Panel( 'Map AOVs' )
p.addEnumerationPulldown( 'texture', ' '.join( layers ) )
p.addEnumerationPulldown( 'diffuse', ' '.join( layers ) )
p.addEnumerationPulldown( 'specular', ' '.join( layers ) )

需要用户指定哪个通道包含深度信息,因此添加一个depth菜单,并给菜单添加通道名:

p.addEnumerationPulldown( 'depth', ' '.join( channels ) )

最后,添加两个复选框来设置是否归一化深度缓冲区(默认勾选)或者反转(默认关闭):

p.addBooleanCheckBox( 'normalise depth', True)
p.addBooleanCheckBox( 'invert depth', False )

简单的小界面就做完了。

注意: 想加更多控制和复杂功能,请看python panels

使用show()来显示界面。 这样打开界面是模式对话框(非模式对话框在此章节木有)。使用OK关闭窗口返回True,使用Cancel关闭返回False:

if not p.show():
    return 

如果取消了,代码就此停止运行。 否则,使用value()将选中的panel存入变量中,名字是panel上的。

texture = p.value( 'texture' )
diffuse = p.value( 'diffuse' )
spec = p.value( 'specular' )
depth = p.value( 'depth' )
normZ = p.value( 'normalise depth' )
invertZ = p.value( 'invert depth' )

现在利用panel中的信息建立节点树吧。

首先,为了以后处理方便,将texture,diffuse,specular缓冲区 导入rgb中。

注意: 从合成角度来说没必要这么干,因为可以将所有层、缓冲区内联合并起来,但保险起见我们用了shuffle节点

使用nuke.nodes 来创建Shuffle节点,节点标签为texture,将其连接到当前节点上:

shuffleNode = nuke.nodes.Shuffle( label='texture', inputs=[node] )

现在,设置inknob读取panel中指定的层来包含纹理信息:

shuffleNode['in'].setValue(layer)

接下来,打开Shuffle节点的邮戳,附加一个Dot节点保持紧凑的布局:

shuffleNode['postage_stamp'].setValue( True )
nuke.nodes.Dot( inputs=[ shuffleNode ] )

同样的事diffuse,specular层也要来一遍,所以把上面的代码封装成函数,方便重用:

def shuffleLayer( node, layer ):
    shuffleNode = nuke.nodes.Shuffle( label=layer, inputs=[node] )
    shuffleNode['in'].setValue( layer )
    shuffleNode['postage_stamp'].setValue( True )
    return nuke.nodes.Dot( inputs=[ shuffleNode ] )

返回autoComp函数(在panel保存变量之后)调用新函数给每个层创建Shuffle节点:

texNode = shuffleLayer( node, texture )
diffNode = shuffleLayer( node, diffuse )
specNode = shuffleLayer( node, spec )

至此所有代码如下:

def shuffleLayer( node, layer ):
    '''
    Shuffle a given layer into rgba
    args:
       node  - node to attach a Shuffle node to
       layer - layer to shuffle into rgba
    '''
    shuffleNode = nuke.nodes.Shuffle( label=layer, inputs=[node] )
    shuffleNode['in'].setValue( layer )
    shuffleNode['postage_stamp'].setValue( True )
    return nuke.nodes.Dot( inputs=[ shuffleNode ] )

def autoComp( node ):
    channels = node.channels()
    layers = list( set([c.split('.')[0] for c in channels]) )
    layers.sort()
    # CREATE SIMPLE PANEL TO MAP THE BUFFERS
    p = nuke.Panel( 'Map AOVs' )
    p.addEnumerationPulldown( 'texture', ' '.join( layers ) )
    p.addEnumerationPulldown( 'diffuse', ' '.join( layers ) )
    p.addEnumerationPulldown( 'specular', ' '.join( layers ) )
    p.addEnumerationPulldown( 'depth', ' '.join( channels ) )
    p.addBooleanCheckBox( 'normalise depth', True)
    p.addBooleanCheckBox( 'invert depth', False )
    if not p.show():
        return
    # STORE PANEL RESULt IN VARIABLES FOR EASE OF USE
    texture = p.value( 'texture' )
    diffuse = p.value( 'diffuse' )
    spec = p.value( 'specular' )
    depth = p.value( 'depth' )
    normZ = p.value( 'normalise depth' )
    invertZ = p.value( 'invert depth' )
    # CREATE SHUFFLE NODES
    texNode = shuffleLayer( node, texture )
    diffNode = shuffleLayer( node, diffuse )
    specNode = shuffleLayer( node, spec )

现在运行脚本会产生三个Shuffle节点,将panle中指定的层倒入到rgba中:


给diffuse缓冲区添加一个Multiply节点,用户可以修改缓冲区,并和shuffle节点的texture合并:

mergeDiff = nuke.nodes.Merge2( operation='multiply', inputs=[ texNode, nuke.nodes.Multiply( inputs=[diffNode] ) ], output='rgb' )

上面那行代码做了如下事情:

  • 创建Merge2节点
  • 将操作knob设置成multiply
  • 输入连接到texture节点,另一个输入(a)连接到新创建的Multiply节点
  • Multiply节点连接到diffuse节点
  • Merge节点的输出设置成**rgb,因此原生a通道完整保存下来

创建另一对Multiply和Merge节点,这次是给specular节点,将这个Merge节点连接到上面创建的Merge节点:

result = nuke.nodes.Merge2( operation='plus', inputs=[ mergeDiff, nuke.nodes.Multiply( inputs=[specNode] ) ], output='rgb' )

查看用户是否要归一化深度,如果是,运行getMinMax函数,在Grade节点中使用其结果:

if normZ:
    black, white = examples.getMinMax( node, depth )
    result = nuke.nodes.Grade( channels=depth, blackpoint=black, whitepoint=white, white_clamp=True, label='normalise depth', inputs=[result] )

检查是否反转深度通道,如果是,使用Invert节点,通道设置成depth:

if invertZ:
    result = nuke.nodes.Invert( channels=depth, inputs=[result] )

最终,添加Grade节点稍微提升下深度通道中的黑色:

g = nuke.nodes.Grade( inputs=[result] )
g['black'].setValue( 0.05 )
g['mask'].setValue( depth )

节点图如下:


所有代码如下:

import examples
import nuke

def shuffleLayer( node, layer ):
    '''
    Shuffle a given layer into rgba
    args:
       node  - node to attach a Shuffle node to
       layer - layer to shuffle into rgba
    '''
    shuffleNode = nuke.nodes.Shuffle( label=layer, inputs=[node] )
    shuffleNode['in'].setValue( layer )
    shuffleNode['postage_stamp'].setValue( True )
    return nuke.nodes.Dot( inputs=[ shuffleNode ] )

def autoComp( node ):
    channels = node.channels()
    layers = list( set([c.split('.')[0] for c in channels]) )
    layers.sort()
    # CREATE SIMPLE PANEL TO MAP THE BUFFERS
    p = nuke.Panel( 'Map AOVs' )
    p.addEnumerationPulldown( 'texture', ' '.join( layers ) )
    p.addEnumerationPulldown( 'diffuse', ' '.join( layers ) )
    p.addEnumerationPulldown( 'specular', ' '.join( layers ) )
    p.addEnumerationPulldown( 'depth', ' '.join( channels ) )
    p.addBooleanCheckBox( 'normalise depth', True)
    p.addBooleanCheckBox( 'invert depth', False )
    if not p.show():
        return
    # STORE PANEL RESULt IN VARIABLES FOR EASE OF USE
    texture = p.value( 'texture' )
    diffuse = p.value( 'diffuse' )
    spec = p.value( 'specular' )
    depth = p.value( 'depth' )
    normZ = p.value( 'normalise depth' )
    invertZ = p.value( 'invert depth' )
    # CREATE SHUFFLE NODES
    texNode = shuffleLayer( node, texture )
    diffNode = shuffleLayer( node, diffuse )
    specNode = shuffleLayer( node, spec )
    
    mergeDiff = nuke.nodes.Merge2( operation='multiply', inputs=[ texNode, nuke.nodes.Multiply( inputs=[diffNode] ) ], output='rgb' )
    result = nuke.nodes.Merge2( operation='plus', inputs=[ mergeDiff, nuke.nodes.Multiply( inputs=[specNode] ) ], output='rgb' )
    
    if normZ:
        black, white = examples.getMinMax( node, depth )
        result = nuke.nodes.Grade( channels=depth, blackpoint=black, whitepoint=white, white_clamp=True, label='normalise depth', inputs=[result] )
    if invertZ:
        result = nuke.nodes.Invert( channels=depth, inputs=[result] )
    
    g = nuke.nodes.Grade( inputs=[result] ) 
    g['black'].setValue( 0.05 )
    g['mask'].setValue( depth )
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容