【NUKE教程】Nuke Python 立体

10 九月, 2016
14
0

nukepythonliti
在nuke中如何处理立体

多视图knob 的数值

给立体项目的每个view中添数值,就跟向translate的x,y knob添加一样。代码添加Transform节点,并将右view分离出来:

n = nuke.createNode('Transform')
k = n['translate']
k.splitView('right')

当分离出一个view时,所有的un-split view像一个main view一样在一起控制,因此,如果没有指定view,所有的un-split knob都会改变。
下面将main view的knob的值设置为1,但分离view除外:

	
k.setValue(1)

Nuke Python 立体

将右侧view的值设置为2:

	
k.setValue(2, view='right')

Nuke Python 立体

将main view的translate设置为 x=1, y=2

k.setValue(1,0)
k.setValue(2,1)

Nuke Python 立体

right view的translate设置成 x=3, y=4

k.setValue(3, 0, view='right')
k.setValue(4, 1, view='right')

Nuke Python 立体

在不同view里面可以用同样的方式创建动画,将main view设置为可动画:

	
k.setanimated()

右侧视图可动画:

	
k.setAnimated( view='right')

main和right view的1-100帧设置关键帧:

k.setValueAt( 50, 1)
k.setValueAt(70, 100)
k.setValueAt(80, 1, view='right')
k.setValueAt(110, 100, view='right')

为两个view渲染动画值:

mainX = k.valueAt(50, 0)
mainY = k.valueAt(50, 1)
rightX = k.valueAt(50, 0, view='right')
rightY = k.valueAt(50, 1, view='right')
print 'left (main) view values at frame 50 are X=%s, Y=%s' %(mainX, mainY)
print 'right view values at frame 50 are X=%s, Y=%s' % (rightX, rightY)
Result:
left (main) view values at frame 50 are X=59.898989898, Y=59.898989898
right view values at frame 50 are X=94.8484848507, Y=94.8484848507

例子

创建、转换立体camera

下面有一个例子,用常用的函数,两个参数,一个定义camera节点,一个定义视距。node默认值为none(这种情况创建新camera)视距只
要能工作就行:

def serreoCam( node=None, interoc=.6 ):
    try:
        node = node or nuke.selectedNode()
    except ValueError:
        node = nuke.createNode( 'Camera2' )

接下来我们获取当前脚本的视图。假设列表中的第一个视图是左眼,第二个是右眼:

	
views = nuke.views() leftView = views[0] right = views[1]

根据给定的视距值计算摄像机的左右偏移:

rightOffset = float( interoc)/2
leftOffset = -rightOffset

可以用matrix或者transform knob来驱动camera。来开始第一个例子,抓取matrix knob并拷贝当前矩阵,就可以创建第二只眼睛。

if node['useMatrix'].value():
    knob = node['matrix']
    leftEyeMatrix = node['transform'].value()
    rightEyeMatrix = nuke.math.Matrix4( leftEyeMatrix )

基于上面计算的左眼值,将原始矩阵移动到左边,右眼照做:

leftEyeMatrix.translate( leftOffset, 0, 0)
rightEyeMatrix.translate( rightOffset, 0, 0)

因为node[‘transform’].value() 返回的矩阵是逆序的,使用前需要反转回来。

leftEyeMatrix.transpose()
rightEyeMatrix.transpose()

如果脚本中只有两个view,就使用左眼作为主view,仅分离出右view,如果多于两个view,就都分离出来:

if len(views) >2:
    knob.splitView( leftView)
knob.splitView( rightView)

现在将4×4的矩阵循环赋值给其他了:

for i in range(16):
    knob.setValue( leftEyeMatrix[i], nuke.frame(), i, leftView)
    knob.setValue( rightEyeMatrix[i], nuke.frame(), i, rightView)

这会关心摄像机被matrix knob的哪个部分驱动,其他例子中,事情简单点但是我们做的事情一样。抓取transform knob的x值和并
按照从视距计算出来的值来offset:

else:
    knob = node['translate']
    leftEye = knob.value(0) + leftOffset
    rightEye = knob.value(0) +rightOffset

按要求分割knob:

if len( views) >2:
        knob.splitView( leftView )
knob.splitView( rightView )

将新值赋给新view

knob.setValue( leftEye, 0, view=leftView )
knob.setValue( rightEye, 0, view = rightView )

最终代码:

import nuke
def stereoCam( node=None, interoc=.6 ):
    '''
    Create a simple stereo camera or convert an existing one.
    args:
       node - camera node to convert to stereo. if None a camera will be created
       interoc  -  distance between right and left view
    '''
    try:
        node = node or nuke.selectedNode()
    except ValueError:
        # IF NO NODE IS GIVEN AND NOTHING IS SELECTED, CREATE A NEW NODE
        node = nuke.createNode( 'Camera2' )
    # GET SCRIPT SETTIONGS' VIEWS
    views = nuke.views()
    leftView = views[0]
    rightView = views[1]
    # THE OFFSET AS REQUESTED
    rightOffset = float(interoc)/2
    leftOffset = -rightOffset
    # THE KNOB TO SPLIT
    if node['useMatrix'].value():
        knob = node['matrix']
        leftEyeMatrix = node['transform'].value() # GETS MATRIX BUT IN REVERSE ORDER
        rightEyeMatrix = nuke.math.Matrix4( leftEyeMatrix ) # COPY MATRIX
        # GET THE NEW VALUES FOR LEFT AND RIGHT EYE
        leftEyeMatrix.translate( leftOffset, 0, 0 )
        rightEyeMatrix.translate( rightOffset, 0, 0 )
        # REVERSE FOR ASSIGNMENT
        leftEyeMatrix.transpose()
        rightEyeMatrix.transpose()
        # IF THERE ARE MORE THAN 2 VIEWS MAKE SURE TO SPLIT OFF LEFT VIEW AS WELL
        if len( views ) > 2:
            knob.splitView( leftView )
        knob.splitView( rightView )
        # ASSIGN VALUES
        for i in range(16):
            knob.setValueAt( leftEyeMatrix[i], nuke.frame(), i, leftView )
            knob.setValueAt( rightEyeMatrix[i], nuke.frame(), i, rightView )
    else:
        knob = node['translate']
        # GET THE NEW VALUES FOR LEFT AND RIGHT EYE
        leftEye = knob.value(0) + leftOffset
        rightEye = knob.value(0) + rightOffset
        # IF THERE ARE MORE THAN 2 VIEWS MAKE SURE TO SPLIT OFF LEFT VIEW AS WELL
        if len( views ) > 2:
            knob.splitView( leftView )
        knob.splitView( rightView )
        # ASSIGN NEW VALUE
        knob.setValue( leftEye, 0, view=leftView )
        knob.setValue( rightEye, 0, view=rightView )
设置立体

有一种方法自动将新的nuke projects设置为立体(或者通常的多视图)。第一,写一个函数将nuke的project转变成多视图,然后将其
挂接到回调函数上,确保新的root节点创建时运行。

创建新view时需要修改的knob是 nuke.root().knob(‘views’), 此knob木有其他方法来设置view,因此检查其脚本语法:

viewKnob = nuke.root().knob('views')
print viewKnob.toScript()
#result:
left #ff0000
right #00ff00

toScript方法将knob转换成脚本语法,就像.nk文件中那样,并是分析复杂knob的好方法。这个例子中,会查出root view的名字,相关的
颜色代码 16进制形式。view通过线来分割。有了这个信息,我们可以重建自己的名字和颜色列表。然后使用fromScript方法来初始化我们的值:

先检测:

veiwKnob = nuke.root().knob('views')
viewKnob.fromScript( 'testView #ff000')

root的view knob有叫做testView的单一视图,并将最初的红色付给他。实际上,想赋值红色要比使用16进制码简单的多。因此,写一个
小工具来转换这个过程,使用python的字符格式化工程,小case。

下面将一个int转换成hex值:

intValue = 255
hexValue = '%x' % intValue
print hexValue

用这个来操作r,g,b

rgb= (255, 0, 0)
hexCol = '#%02x%02x%02x' % rgb
print hexCol

既然nuke大部分都工作在浮点数据模式下,稍微修改下,就能输入0-1而不是八位int 0-255:

col = ( .5, .3, .2)
rgb = tuple( [int(v*255) for v in col ] )
hexCol = '#02x%02x%02x' % rgb
print hexCol
# Result:
#7f4c33

上面的代码会将每个正规化的浮点值col 变换成 8位整形。 输出是一个列表,其在存储到rgb前被转换成tuple。
将所有的东西放在一起来构建testView的view,并赋给黑红色。

name = 'testView'
col = (.5, 0, 0)
rgb = tuple( [int(v*255) for v in col ])
hexCol = '#%02x%02x%02x' % rgb
view = '%s %s ' %(name, hexCol)
nuke.root().knob('views'), fromScript( view)

如果想要不止一个view,会在多个view间有一条线:

newViews = []
name = 'testView'
col = (.5, 0, 0)
rgb = tuple([ int(v*255) for v in col ])
hexCol = '#%02x%02x%02x' % rgb
view = '%s %s' % (name, hexCol)
newViews.append(view)
name2 = 'testView2'
col2 = (0, .5, 0)
rgb2 = tuple([ int(v*255) for v in col2 ])
hexCol2 = '#%02x%02x%02x' % rgb2
view2 = '%s %s' % (name2, hexCol2)
newViews.append(view2)
nuke.root().knob('views').fromScript('\n'.join(newViews))

现在将其整理下,添加nuke的import,创建一个函数,参数为元组,view的名字,以及颜色:

import nuke
def setUpMultiView( views=[ ('left',(0,1,0)), ('right',(1,0,0) ) ] ):
    '''
    set up the nuke project with an arbitrary amount of colour coded views
    args:
       views  -  nested list with view names and rgb tuples for each view. rgb values are assumed to be normalise, eg red = (1,0,0)
    '''
    newViews = []
    for v in views:   # CYCLE THROUGH EACH REQUESTED VIEW
        name = v[0]   # GRAB THE CURRENT VIEWS NAME
        col = v[1]    # GRAB THE CURRENT VIEWS COLOUR
        rgb = tuple( [ int(v*255) for v in col ] ) #CONVERT FLOAT TO 8BIT INT AND RETURN A TUPLE
        hexCol = '#%02x%02x%02x' % rgb             #CONVERT INTEGER NUMBERS TO HEX CODE
        curView = '%s %s' % ( name, hexCol )       #COMBINE NAME AND HEX COLOUR TO SCRIPT SYNTAX
        newViews.append( curView )      # COLLECT ALL REQUESTED VIEWS
    # COMBINE ALL VIEWS WITH LINE BREAK AND INITIALISE THE VIEWS KNOB WITH THE RESULTING SCRIPT SYNTAX
    nuke.root().knob('views').fromScript( '\n'.join( newViews ) )

运行来测试下,注意上面的函数定义了左右视图,红蓝色。因为没有任何参数也可以运行此函数:

setUpMultiView()

如果想要左边view为红色,右边为绿色,用不同的值来调用:

setUpMultiView( [('left', (1,0,0)), ('right', (0,1,0)])

创建了left和right的两个view,分别为红色和绿色:
Nuke Python 立体

如果想要nuke在启动的时候运行次脚本,在立体模式下会自动创建新session,将函数挂载在onUserCreate上。