在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)
将右侧view的值设置为2:
k.setValue(2, view='right')
将main view的translate设置为 x=1, y=2
k.setValue(1,0)
k.setValue(2,1)
right view的translate设置成 x=3, y=4
k.setValue(3, 0, view='right')
k.setValue(4, 1, view='right')
在不同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)
现在将4x4的矩阵循环赋值给其他了:
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在启动的时候运行次脚本,在立体模式下会自动创建新session,将函数挂载在onUserCreate上。