TimeOffset Keyframes and Lifetime

TimeOffset Keyframes and Lifetime

TimeOffset all the Keyframes, Lifetime, Rotopaint and Shapes in your nodes

With this Python tools for The Foundry Nuke, you can time offset all the keyframes and Lifetime of a single node. It includes all the brushes into a RotoPaint node and all the shapes of Roto nodes
Just select the node you prefer and launch this Python script.

It's Python3 and Nuke 13+ ready!
Download the script




Useful Links



Overview

  • TIME OFFSET ALL THE ATTRIBUTES

Let's start with this Python code.
The easiest way is to open the Script Editor in Nuke and use this simple code.
Copy this code into the Script Editor, select node you want to treat and launch the code. Select it all with CTRL+A and press CTRL+ENTER.








import nuke, re
import nukescripts
import nuke.rotopaint as rp
import _curvelib


############################################
######## CREATE PANEL ######################
############################################
class OffsetAnimation( nukescripts.PythonPanel ):
    def __init__( self, node ):
        self._selectedNode = nuke.selectedNode()


        nukescripts.PythonPanel.__init__( self, 'Offset Animation: ' + self._selectedNode.name())
        self.offsetValue = nuke.Int_Knob( 'offsetValue', 'Offset frames:' )
        
        self.addKnob( self.offsetValue )


############################################
########## show PANEL ######################
############################################
def showPanel():
    panel = OffsetAnimation(nuke.selectedNode())

    dialog = panel.showModalDialog()

    if not dialog:
        nuke.message("NO TIMEOFFSET APPLIED")
    else:
        #array = panel._selectedNode[panel.knob.value()].arraySize() #get number of Array for the knob selected
        
        node = nuke.selectedNode()
        offset = panel.offsetValue.value()
    
    ############################################
    ######### OFFSET ANIMATIONS ################
    ############################################
    
    
        """
        This function will slip all the animations of the passed node by a passed
        offset in frames
        
        The animations are offset in the passed TCL curve command.
        In this script every frame at which keys are placed is marked by x,
        and these are only placed at the start of a non-continuous segment.
        Instead of mucking about with AnimationKey objects (which we also
        can inadvertently slip behind their following keys), we take the whole curve
        and replace all these commands by their respective slipped values
        """
        def offset_frames_in_curve(curve_str, offset):
            def offset_replace(m):
                # Try to preserve float/int distinction
                if "." in m.group(1):
                    return "x%0.3f" % (float(m.group(1)) + offset)
                else:
                    return "x%d" % (int(m.group(1)) + offset)
            return re.sub(r"x([-+]?\d*\.\d+|\d+)", offset_replace, curve_str)
        
        # Walk all the knobs of the object and check if they are animated.
        for knob_name in node.knobs():
            k = node[knob_name]
            if k.isAnimated():
                k.fromScript(offset_frames_in_curve(k.toScript(), int(offset)))
    
        
        #If Lifetime of the node is active
        if node.knob('useLifetime').getValue() == 1:
            if nuke.ask('Do you want to offset the Lifetime of the node as well?'):
                node.knob('lifetimeStart').setValue(node.knob('lifetimeStart').getValue()+offset)
                node.knob('lifetimeEnd').setValue(node.knob('lifetimeEnd').getValue()+offset)
    
    
        ############################################
        ### OFFSET THE LIFETIME in the ROTONODE ####
        ############################################
        
        if (nuke.selectedNode().Class() == "Roto" or nuke.selectedNode().Class() == "RotoPaint"):
            if nuke.ask('Do you want to offset the Lifetime for each Shape and Stroke?'):
                rotoNode = nuke.selectedNode()
                cKnob = rotoNode['curves']
                rootLayer = cKnob.rootLayer
                
                for i in rootLayer:
                    if isinstance(i, rp.Stroke):
                
                        attribs = i.getAttributes()
                        start = int(attribs.getValue(0,_curvelib.AnimAttributes.kLifeTimeNAttribute))
                        end = int(attribs.getValue(0,_curvelib.AnimAttributes.kLifeTimeMAttribute))
                        type = int(attribs.getValue(0,_curvelib.AnimAttributes.kLifeTimeTypeAttribute))
                        
                        
                        attribs.set(0,_curvelib.AnimAttributes.kLifeTimeNAttribute, start+offset )
                        attribs.set(0,_curvelib.AnimAttributes.kLifeTimeMAttribute, end+offset )        
        
        
            nuke.message("Now go into the Dope Sheet, select all the Brushes and Strokes, put the offset in the bottom-left corner and press MOVE")
         
#############################################
    
    
if len(nuke.selectedNodes()) == 1:
    showPanel()
else:
    nuke.message("Select only one node")


Leave a comment