Use of expressions to modify animation curves

Written by Ivan Busquets on .

 

Timing changes can be quite a headache in most compositing packages.
Here's a few cases where the use of expressions can be of great help when dealing with time modifiers (frame holds, time offsets, time warps…)



1- Freezing an animation to a certain frame (FrameHold)

The syntax curve(frame) is one of the simplest and yet most useful ways to handle time within an expression. It means "take the value of this animation (curve), at this frame".
This can be used on any animated knob, but it's most useful on 3d operators, since one cannot simply attach a FrameHold node to them (yet).

Here's a very common scenario: you have a plate and a matchmoved camera and want to set up a projection based on a still frame from the plate. You can either make a copy of your camera and delete its animation to make it static at the frame of your choice, or use an expression to dynamically freeze the camera's animation based on a separate FrameHold, which you can later change if you wish to choose a different frame for your projection.

 

frameHold

frameHold_expThe above setup can be easily accomplished by using the following expression in any animated knob in the projection camera:

 

 

 

The same expression can be used in the label of the projection camera to show the frame being used at all times. Like this:

labelHold

 


 

- Offseting an animation in time (TimeOffset)

This works almost identically to the previous case.
Let's say you have a camera that matches your plate. Now, in your comp, you're offsetting that plate in time.
You can still dynamically reference the animation of the camera by using a curve(frame+offset) expression.

Like this:

timeOfssettimeOffset_exp

 


 

- Retiming an animation (TimeWarp, OFlow, F_Kronos)

Again, using the same expression syntax, a retime curve can also be referenced so your animation is retimed the same way your footage is.

Here's an example using the retime data from a Timewarp node to retime the animation of a Transform node:

timeWarp

If you're using a OFlow or F_Kronos, you'll have to reference the "timingFrame" and "frame" knobs respectively, instead of the lookup knob.

Additionally, OFlow and F_Kronos can use two different methods to describe a retime: a lookup curve (source frame) or an overall speed.

If you want your expression to work correctly regardless of the method used, you could include a condition so it handles both methods. This way you can work on your OFlow or F_Kronos as you like, and make sure your animation curves carry those changes live.

Here's how the expressions would look like for all three kind of nodes:

timeWarp_options


 

- Inverting a retime curve (undoing a retime using the "inverse" expression)

 
Say you have a retime curve you need to get the inverse of. For example, you animated (or tracked) something to an already retimed plate, and now that retime has changed. Ideally, you'd want to un-apply the first retime from your curve, and then apply the new one.


There's at least 2 ways in which you could approach this:

  1. Take the old retime curve, and invert it in the Curve Editor by doing Edit->Move… and then switch the x and y values of the curve. From here, you can apply this "inverted" curve to your animation curve as described in "Retiming an animation"
  2. Use the built in "inverse" expression method. This is ideal if you're still making changes to the original curve. However, keep in mind the "inverse" method will only work on curves that have a positive derivative everywhere. In other words, it only works with curves/retimes where the frame number only increases (ie., no backwards retime, ping-pongs, or anything where the frame number decreases with time)

 

To use the inverse method, just use curve.inverse, or nodename.knobname.inverse, where nodename.knobname contains an animation curve. Like this:

inverseTimeWarp

 


 

- Finding the slope/speed of a curve at a certain point (derivative expression)

The derivative expression can be very handy for motion graphics, or in any scenario where you'd like to animate something depending on the "speed" of an animated curve.

Imagine you have a retime curve and you want to do some creative grading as your clip slows down/speeds up. Or, you have tracked an object (a magic wand, for example), and want it to get brighter the faster it moves. Or, you're animating a wheel, and want it to rotate faster the faster it moves across the screen. You get the picture. In all of these cases, the derivative expression can be of great help.

How to use it:

The syntax is curve.derivative, and it will return the first derivative of that curve at the current frame. That is, how much do the values in the current curve change between the current frame and the next. This illustration explains it better:

derivative2

So, by using the expression curve.derivative on the above curve, you get 1 for frames 1 to 9, 0 on frame 10, -2 on frames 11 to 14, and then 0 again on frame 15.

It is then up to you to use those values on any other knob, and modify them as needed (normalize them, scale them...) so they're suited for your purpose (rotation, color correction,...).

The derivative expression can take 2 optional values, with the one of the following syntaxes:

  • curve.derivative(frame)
  • curve.derivative(n, frame)

- frame is the frame we're calculating the derivative for. Default is the current frame. You could use something like curve.derivative(1,frame-5) to get the first derivative of this curve with a delay of 5 frames, for example.

- n represents the nth derivative. The default is one (for first derivative), but you can set it to 2 to return the second derivative. The second derivative can be described as the derivative of the first derivative. A good analogy of what that means is: on a moving car, the first derivative would be its change in position along time (=speed), and the second derivative would be the change in speed along time (=acceleration). So, if you want to animate something to the acceleration of an object instead of its speed, try the second derivative.


 

- Finding the average of a curve (integrate expression)

  
The integrate of a curve between points A and B is usually described as the area below that curve for that slice (A to B). Integration is also often used to find the average value of a function (curve) between two points. This can come in quite handy for complex curves, so let's see how we can use it in Nuke to get the average value of a curve between two frames:

Say you have a curve that produces a flickering effect. Something like this:

RandomCurve

Now you want to know the average value of that curve between frames 0 and 100. You can do so using an expression with the following syntax:

curve.integrate(first frame, last frame)/(number of frames)

This would calculate the integrate of a curve between 'first frame' and 'last frame'. The result would be the aggregate of values between the 2 specified frames, or the area below that slice of the curve. So, dividing that by the total number of frames, we get the average value. Using the above curve as an example, the expression field would look like this:

Average

Comments   

 
+4 # behram patel 2010-10-09 03:49
the most simplest & practical explanation of a derivative in any CG related material i have ever read.
Huge thanks to you Ivan

b

 
 
0 # Aled Rhys Jones 2011-03-23 11:02
Although I now know derivatives, how do I apply it? my example is a 1pt track and I want the x value to affect the rotation of the object I'm attaching to it.
How would I write the expression into the Rotation given that my input would be "Tracker1.track1.x"?

Just a little note that I haven't yet learned expressions with Nuke, though I did use them quite a bit with After Effects.
 
 
0 # behram patel 2011-03-25 00:33
Hey Aled,
Try
translate.x.derivative()

b
 
 
0 # Marko Zaric 2012-01-03 11:41
Hi Ivan.

Great explanations!

but I have a question.

Is there a way to connect time offset and switch?

concrete:
I have time offset node at frame 35 and i want my switch to be 0 until then, and to 1 at frame 36
Is this even possible?

thanks in advance
Marko
 
 
-1 # Ivan Busquets 2012-01-03 15:06
Hi Marko,

I'm not sure I understand the question, but here's a couple of tips that might be what you're after:
To have your Switch node switch from 0 to 1 at frame 35, you could use an expression like:

frame>=35

If, instead of frame 35, you want to use the frame value of your TimeOffset node, then you could do (assuming your TimeOffset node is called "TimeOffset1"):

frame>=TimeOffset1.time_offset

Is that what you were looking for?

Cheers,
Ivan
 
 
0 # Marko Zaric 2012-01-03 23:31
Hi Ivan.

Thanks for fast answer!
Yes that it exactly what i was looking for. It works like i need it.

Once again thank You very much.

Cheers

Marko
 
 
0 # sridharan K 2012-04-10 02:03
Hy Ivan... thnx for ur valuable information...

I hav a question.... I tracked the plate of 100 frames... Now they want the ping pong of the shot with 200 frames... i achieved the result for my scans... how to do ping pong for my tracking information... is there any expression for that.. plz do needful...
thnx...
 
 
0 # Ivan Busquets 2012-04-11 12:05
Hi sridharan,

There's a couple of things you could do:
You can create a TimeWarp node that matches your ping-pong retime. You would just need a keyframe on the first frame, another one on frame 100, and one last one on frame 199, mapped to your first frame again. Then, in your tracker, you would just use one of the example expressions above (look under "Retiming an animation" to see how you can use a TimeWarp node for that)

Alternatively, if you want to manually set up your expression, it should read something like this:

curve(frame
 
 
0 # Ivan Busquets 2012-04-11 12:08
Ooops, the last comment got cut short...

The expression to set it up manually would read like this for your case:

curve(frame
 
 
0 # Ivan Busquets 2012-04-11 12:13
Ok, so something is weird with the comments system, where typing certain characters cuts the message at that point.

I'll try again, without using those symbols :-)

curve(frame LESS_THAN_OR_EQ UAL_TO 100 ? frame : 200 - frame)

Replace LESS_THAN_OR_EQ UAL_TO with the appropriate characters :-)

Hope that helps
 
 
0 # Chetal Gazdar 2014-06-30 07:25
is there any way to find first and last keyframe number ??
 
 
0 # zaf er 2014-12-15 16:00
Hi, i m a total expression noob , can anyone please guide me where i should start to learn nuke expressions. Thanks.
 
 
0 # swillz oner 2015-08-26 08:50
Hey Ivan, I am trying to apply an Oflow retime to my Nuke camera (which I have imported alembic hoping to export back to 3D) however I when I enter

curve(OFlow1.timing?OFlow1.timingFrame:(frame-OFlow1.first_frame)*OFlow1.speed+OFlow1.first_frame)

I am getting: "nothing is named "Oflow1.speed""
I assumed this is because I am using the Frame timing method as opposed to using an input Speed in my OFlow node.

So I have swapped "OFlow1.speed" for "Oflow1.timingFrame2"
and I'm still not getting the desired results. Any ideas?
 
 
0 # Shahin Toosi 2016-01-21 20:02
i have a bit of a complex question i would like to ask and not quite sure how to ask this but ill have a go at it!

is it possible to extract the Frame where the key was set on a cuve? i would like to link the key frame from a nowhere curve to a frame hold..

thanks you
 
 
0 # Frank Rueter 2016-01-21 20:24
you can use tcl for that, e.g. to grap the value of the second key frame in MyAnimatedNode. myAnimatedKnob you can do this:
[animation MyAnimatedNode. myAnimatedKnob y 1]

Have a look at the tcl command for animation in Help/documentat ion/Tcl Scripting/Nuke tcl commands
 
 
0 # Shahin Toosi 2016-01-21 20:49
Quoting Frank Rueter:
you can use tcl for that, e.g. to grap the value of the second key frame in MyAnimatedNode.myAnimatedKnob you can do this:
[animation MyAnimatedNode.myAnimatedKnob y 1]

Have a look at the tcl command for animation in Help/documentation/Tcl Scripting/Nuke tcl commands

thank so much dude, I'm looking at this now, the manule is starting to give me a headache! animation y1 will give the the 1 key frame, iv looked at the la and ldy but they don't seem to update when the when the slider animated am i doing something wrong!
 
 
0 # Frank Rueter 2016-01-21 20:52
animation y 1 will give you the value of hte second key (index o is the first key). the animation command is a bit of a challenge. what exactly are you trying to do?
 
 
0 # Shahin Toosi 2016-01-21 21:00
basically i have no idea how to articulate it!

trying to connect the the key frame (in x) of animated curve from one knob to a nothre!

e.g. if you got a mult that got 5 key frame for example at frame 1,25,50,100 to connect dose to a frame hold for example! so when you animated the frame hold number updates!

if this makes any sense!

p.s. im getting the feeling that your starting to peas to gather how this is as how badly my spelling going! :P
 
 
0 # Frank Rueter 2016-01-21 21:29
can't you just use something like this?
NodeName.knobName(frame)

e.g. this will give you the value of Blur1.size at frame 10:
Blur1.size(10)
 
 
0 # Shahin Toosi 2016-01-21 21:49
Quoting Frank Rueter:
can't you just use something like this?
NodeName.knobName(frame)

e.g. this will give you the value of Blur1.size at frame 10:
Blur1.size(10)


haaaaa! that one is it the tic was a lot closer to what i was trying to do!

let me past the example.

set cut_paste_input [stack 0]
version 9.0 v6
push $cut_paste_input
NoOp {
name NoOp1
selected true
xpos 149
ypos -67
addUserKnob {20 User}
addUserKnob {3 keyframe l "Frame OF the key"}
keyframe {{"\[animation anime x 1]"}}
addUserKnob {7 anime l "Animated cureve"}
anime {{curve x1 0 x31 0.53 x69 0.24 x99 1}}
}

basically i trying to get the "frame of the key" to up date during play back!
 
 
0 # Frank Rueter 2016-01-21 22:02
but there is nothing to update during playback. the frame of key 2 in your exmaple will always be the same static value during playback. If you move the second key in x, you will see that change reflected in the "Frame of key" knob.
 
 
0 # Shahin Toosi 2016-01-21 22:04
that what I'm asking how do i get it to update?
 
 
0 # Frank Rueter 2016-01-21 22:07
it is updating as it should, you may be expecting the wrong thing (or I'm misunderstanding).
Your expression returns the frame number (x value) of the second key in the animation curve. that doesn't change during playback. The second key is always on the same frame unless you move it (in which case your expression updates).
 
 
0 # Shahin Toosi 2016-01-21 22:10
i think I'm just confusing every thing! thank you frank your always awesome :)
 
 
0 # owen williams 2016-06-24 21:29
is there a way to link a knob value with the node color? I want to make a camera node change color based on a frame hold value. I.e if I kill the animation it changes the nodes color.
 
 
+1 # Norman Cates 2021-08-18 00:49
Sorry to be asking this here...

But where can we find ANY more documentation on Nuke expressions that the tiny amount in the manuals?

The Foundry have made a laughable stab at documentation for their expression engine. They simply don't mention many of the commands you use above. They don't mention conditionals.

This is incredibly frustrating for software this expensive. Even Adobe provides vastly better documentation.
 

You have no rights to post comments

We have 4378 guests and 132 members online