Untitled

mail@pastecode.io avatar
unknown
plain_text
a year ago
8.6 kB
2
Indexable
Never
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)