import nuke
import math
def ConcatTransform_getMatrix(node, frame=nuke.frame()):
if node.Class() == 'Transform':
t = node['translate'].valueAt(frame)
r = node['rotate'].valueAt(frame)
sc = node['scale'].valueAt(frame)
if type(sc) is float:
sc = [sc,sc]
sx = node['skewX'].valueAt(frame)
sy = node['skewY'].valueAt(frame)
p = node['center'].valueAt(frame)
#pivot
pivot = nuke.math.Matrix4()
pivot.makeIdentity()
pivot.translate(-p[0],-p[1],0)
pivot.transpose()
inv = pivot.inverse()
#transform
matrix = nuke.math.Matrix4()
matrix.makeIdentity()
matrix.translate(t[0],t[1],0)
matrix.rotateZ((math.pi/180)*r)
if node['skew_order'].value() == 'XY':
matrix.skewXY(sx,sy)
else:
matrix.skewXY(0,sy)
matrix.skewXY(sx,0)
matrix.scale(sc[0],sc[1],1)
matrix.transpose()
matrix = pivot*matrix*inv
if node['invert_matrix'].value():
matrix = matrix.inverse()
return matrix
elif node.Class() == 'CornerPin2D':
to1x, to1y = node['to1'].valueAt(frame)
to2x, to2y = node['to2'].valueAt(frame)
to3x, to3y = node['to3'].valueAt(frame)
to4x, to4y = node['to4'].valueAt(frame)
from1x, from1y = node['from1'].valueAt(frame)
from2x, from2y = node['from2'].valueAt(frame)
from3x, from3y = node['from3'].valueAt(frame)
from4x, from4y = node['from4'].valueAt(frame)
To = nuke.math.Matrix4()
From = nuke.math.Matrix4()
To.mapUnitSquareToQuad(to1x,to1y,to2x,to2y,to3x,to3y,to4x,to4y)
From.mapUnitSquareToQuad(from1x,from1y,from2x,from2y,from3x,from3y,from4x,from4y)
matrix = To*From.inverse()
matrix.transpose()
extraMatrix = nuke.math.Matrix4()
for index, value in enumerate(node['transform_matrix'].getValueAt(frame)):
extraMatrix[index] = value
matrix = matrix*extraMatrix
if node['invert'].value():
matrix = matrix.inverse()
return matrix
def ConcatTransform_concatMatrix(node, frame=nuke.frame()):
#collect transforms
look = True
un = node.input(1)
tn = []
while look:
if un is None:
look = False
elif un.Class() in ['Dot', 'NoOp']:
un = un.input(0)
elif un.Class() == 'Switch':
un = un.input(int(un['which'].valueAt(frame)))
elif un.Class() in ['Transform', 'CornerPin2D']:
if not un['disable'].valueAt(frame):
tn.append(un)
un = un.input(0)
else:
look = False
tn = list(reversed(tn))
#return identity matrix if no nodes found
if len(tn) == 0:
matrix = nuke.math.Matrix4()
matrix.makeIdentity()
return matrix
#get concatinated matrix
matrix = ConcatTransform_getMatrix(tn[0], frame)
for i in tn[1:]:
matrix = matrix * ConcatTransform_getMatrix(i, frame)
#compensate for ref frame
if node['use'].value():
rframe = int(node['ref'].value())
refMatrix = ConcatTransform_getMatrix(tn[0], rframe)
for i in tn[1:]:
refMatrix = refMatrix * ConcatTransform_getMatrix(i, rframe)
refMatrix = refMatrix.inverse()
matrix = matrix * refMatrix
#invert if wanted
if node['invert'].value():
matrix = matrix.inverse()
return matrix
def ConcatTransform_detectCP(node):
look = True
un = node.input(1)
cornerpin = False
while look:
if un is None:
look = False
elif un.Class() in ['Dot', 'NoOp', 'Transform']:
un = un.input(0)
elif un.Class() == 'Switch':
un = un.input(int(un['which'].valueAt(frame)))
elif un.Class() == 'CornerPin2D':
if un['disable'].value():
un = un.input(0)
else:
cornerpin = True
look = False
else:
look = False
return cornerpin
def run():
node = nuke.thisNode()
width = node.width()
height = node.height()
#determine whether to create a Transform or CornerPin
op = node['outputNode'].value()
if op == 'CornerPin':
cornerpin = True
elif op == 'Transform':
if ConcatTransform_detectCP(node) and not nuke.ask('A CornerPin is detected upstream, a transform might not be able to faithfully recreate the resulting matrix. continue?'):
return
cornerpin = False
elif op == 'Detect':
cornerpin = ConcatTransform_detectCP(node)
#set range
if node['noAnim'].value():
frames = [nuke.frame()]
else: #multiple frames
start = int(nuke.root()['first_frame'].value())
end = int(nuke.root()['last_frame'].value())
retu = nuke.getFramesAndViews('bake range', str(start) + '-' + str(end))
try:
r = [int(i) for i in retu[0].split('-')]
frames = range(r[0],r[1])
except:
return
#find group name if node is in group
fnn = node.fullName().split('.')
groupName = 'root.'
for i in range(len(fnn)-1):
groupName += fnn[i] + '.'
#get parent
if groupName != 'root.':
parent = nuke.toNode(groupName[:-1])
else:
parent = nuke.root()
with parent:
if cornerpin:
#create CornerPin
cp = nuke.nodes.CornerPin2D()
cp['xpos'].setValue(node['xpos'].value()+100)
cp['ypos'].setValue(node['ypos'].value()+50)
cp['from2'].setValue([width,0])
cp['from3'].setValue([width,height])
cp['from4'].setValue([0,height])
cp.showControlPanel()
if not node['noAnim'].value():
cp['to1'].setAnimated()
cp['to2'].setAnimated()
cp['to3'].setAnimated()
cp['to4'].setAnimated()
#convert matrix to cornerpin values
for frame in frames:
matrix = ConcatTransform_concatMatrix(node, frame)
matrix.transpose()
v1 = nuke.math.Vector4(0, 0, 0, 1)
v1 = matrix.transform(v1)
v1 /= v1.w
v2 = nuke.math.Vector4(width, 0, 0, 1)
v2 = matrix.transform(v2)
v2 /= v2.w
v3 = nuke.math.Vector4(width, height, 0, 1)
v3 = matrix.transform(v3)
v3 /= v3.w
v4 = nuke.math.Vector4(0, height, 0, 1)
v4 = matrix.transform(v4)
v4 /= v4.w
for i in range(2):
cp['to1'].setValueAt(v1[i], frame, i)
cp['to2'].setValueAt(v2[i], frame, i)
cp['to3'].setValueAt(v3[i], frame, i)
cp['to4'].setValueAt(v4[i], frame, i)
else:
#create Transform node
t = nuke.nodes.Transform()
t['xpos'].setValue(node['xpos'].value()+100)
t['ypos'].setValue(node['ypos'].value()+50)
t['center'].setValue([width/2,height/2])
t.showControlPanel()
if not node['noAnim'].value():
t['translate'].setAnimated()
t['rotate'].setAnimated()
t['scale'].setAnimated()
t['skewX'].setAnimated()
#convert matrix to transform values
for frame in frames:
matrix = ConcatTransform_concatMatrix(node, frame)
matrix.transpose()
vector = nuke.math.Vector3(width/2, height/2, 0)
vector_trans = matrix.transform(vector)
delta = (matrix[0] * matrix[5]) - (matrix[4] * matrix[1])
r = pow(matrix[0], 2) + pow(matrix[1], 2)
translate_x = vector_trans[0] - width/2
translate_y = vector_trans[1] - height/2
rotation = math.degrees(math.atan2(matrix[1], matrix[0]))
scale_x = math.sqrt(r)
scale_y = delta / scale_x
skew_x = (matrix[0] * matrix[4] + matrix[1] * matrix[5]) / delta
t['translate'].setValueAt(translate_x, frame, 0)
t['translate'].setValueAt(translate_y, frame, 1)
t['rotate'].setValueAt(rotation, frame)
t['scale'].setValueAt(scale_x, frame, 0)
t['scale'].setValueAt(scale_y, frame, 1)
t['skewX'].setValueAt(skew_x, frame)