Use of expressions to modify animation curves
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.
The 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:
- 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:
- 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:
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:
- 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:
- 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"
- 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:
- 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:
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:
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:
Comments
Huge thanks to you Ivan
b
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.
Try
translate.x.derivative()
b
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
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
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
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...
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
The expression to set it up manually would read like this for your case:
curve(frame
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
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?
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
[animation MyAnimatedNode. myAnimatedKnob y 1]
Have a look at the tcl command for animation in Help/documentat ion/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!
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!
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!
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).
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.
RSS feed for comments to this post