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")