Blackmagic Fusion Simple Expressions-Cookbook + Tutorial

I will explain the following examples in depth, if you just want the code in a neat table click here.

if() Expression

This is another common Expression that is very useful. You can use an iif() Expression to set a value based on a condition.

The syntax works like this:

iif(Condition is true, return this, else this)

So to change the Size on a Text+ after a certain frame we can write this Expression:

iif(time>10, 0.3, 0.08)

This will change the Size from 0.08 to 0.3 after frame 10.

if() to speed up rendering

The next example is something I use quite often when working on bigger projects that take quite some time to render. While working on it, you want to see your changes as fast as possible and Fusion has a few inbuilt features to ensure that. One is to disable the HiQ-Mode. You can see this quite well with the Resize or the DirectionalBlur tool.

Here is a simple Text+ tool with a Resize tool. I enabled the Only use Filter in HiQ Setting on the Resize tool.

Text+, Resize and DirectionalBlur
Fusions resize tool

Hover over the image below and use the Controls below to toggle between the image in HiQ on and HiQ off. You will see that the Text with HiQ off will look more pixelated. That way Fusion can skip the Filter operation and deliver the image quicker. Not good for final rendering, but great for a quick preview. Try it yourself, for example with the DirectionalBlur tool, or toggle the gallery image below.

	
	
	
Before Image After Image

But why am I telling you this? Because not all computational expensive tools have this option by default. This is where the if() expression will come in handy. Take the Rays tool for example. Having a colorful Text+ tool and the Rays tool animated will already reduce the playback to around 20 frames a second. Now imagine having several in your composition. This will quickly destroy playback performance. What I often do is disable the Rays tool completely when disabling HiQ-mode.

In the Rays tool (or any other tool you want to disable), right-click on the Blend Slider. In the Rays tool you will find this on the first Tab, most other tools have the Blend Slider on the Settings Tab.

Fusions Rays tool

Now type in:

iif(comp.HiQ, 1, 0)

As you remember from this chapter, the expression comp.HiQ will return a boolean (either false or true). This is why we don’t need to specify when this if() Expression will be true. But in the end, it will set the Blend Slider to 0 when HiQ is off, meaning that it will not calculate this node either.

{
Tools = ordered() {
Text1 = TextPlus {
Inputs = {
GlobalIn = Input { Value = 1, },
Width = Input { Value = 1920, },
Height = Input { Value = 1080, },
["Gamut.SLogVersion"] = Input { Value = FuID { "SLog2" }, },
Type1 = Input { Value = 2, },
ShadingGradient1 = Input {
Value = Gradient {
Colors = {
[0] = { 1, 0, 0, 1 },
[0.303482587064677] = { 0.303482587064677, 1, 0.515223880597015, 1 },
[0.532338308457711] = { 0.532338308457711, 0.539820895522388, 1, 1 },
[0.776119402985075] = { 1, 0.980298507462687, 0.776119402985075, 1 },
[1] = { 1, 1, 1, 1 }
}
},
},
StyledText = Input {
Value = "true",
Expression = "Text(comp.HiQ)",
},
Font = Input { Value = "Open Sans", },
Style = Input { Value = "Bold", },
Size = Input {
SourceOp = "Shake2",
Source = "X",
},
VerticalJustificationNew = Input { Value = 3, },
HorizontalJustificationNew = Input { Value = 3, },
ManualFontKerningPlacement = Input {
Value = StyledText {
Array = {
},
Value = ""
},
},
},
ViewInfo = OperatorInfo { Pos = { 275, 82.5 } },
},
Shake2 = Shake {
CtrlWZoom = false,
},
Rays1 = Fuse.OCLRays {
CtrlWZoom = false,
Inputs = {
Center = Input {
SourceOp = "Shake1",
Source = "Position",
},
Blend = Input { Expression = "iif(comp.HiQ, 1, 0)", },
Image = Input {
SourceOp = "Text1",
Source = "Output",
},
},
ViewInfo = OperatorInfo { Pos = { 440, 82.5 } },
},
Shake1 = Shake {
CtrlWZoom = false,
Inputs = {
Smoothness = Input { Value = 16.93, },
XMinimum = Input { Value = 0.378, },
XMaximum = Input { Value = 0.528, },
},
}
}
}

iif() Expression to toggle Vector Motion Blur

Another way to save time is to disable Motion Blur. For that, we have the MB Button in the UI, exactly like the HiQ Button. But this only disables the iterative Motion Blur that is applied by Transform tools for example. The VectorMotionBlur tool is not affected by this. We could hook this up to the HiQ Button and call it a day, but wouldn’t it be cool to have this be controlled by the MB Button instead.

You might think this is as easy as comp.MB but that was never implemented. Luckily, there is another way as explained by the great Peter Loveday here.

Instead of asking the composition if the button is enabled, we can ask the node/tool if it was requested to calculate Motion Blur.

So type in this:

iif(req:IsNoMotionBlur(), 0, 1)
Expression to disable Motion blur
{
Tools = ordered() {
Text1 = TextPlus {
Inputs = {
GlobalIn = Input { Value = 1, },
Width = Input { Value = 1920, },
Height = Input { Value = 1080, },
["Gamut.SLogVersion"] = Input { Value = FuID { "SLog2" }, },
Type1 = Input { Value = 2, },
ShadingGradient1 = Input {
Value = Gradient {
Colors = {
[0] = { 1, 0, 0, 1 },
[0.303482587064677] = { 0.303482587064677, 1, 0.515223880597015, 1 },
[0.532338308457711] = { 0.532338308457711, 0.539820895522388, 1, 1 },
[0.776119402985075] = { 1, 0.980298507462687, 0.776119402985075, 1 },
[1] = { 1, 1, 1, 1 }
}
},
},
StyledText = Input {
Value = "true",
Expression = "Text(comp.HiQ)",
},
Font = Input { Value = "Open Sans", },
Style = Input { Value = "Bold", },
Size = Input {
SourceOp = "Shake2",
Source = "X",
},
VerticalJustificationNew = Input { Value = 3, },
HorizontalJustificationNew = Input { Value = 3, },
ManualFontKerningPlacement = Input {
Value = StyledText {
Array = {
},
Value = ""
},
},
},
ViewInfo = OperatorInfo { Pos = { 275, 82.5 } },
},
Shake2 = Shake {
CtrlWZoom = false,
},
Rays1 = Fuse.OCLRays {
CtrlWZoom = false,
Inputs = {
Center = Input {
SourceOp = "Shake1",
Source = "Position",
},
Blend = Input { Expression = "iif(comp.HiQ, 1, 0)", },
Image = Input {
SourceOp = "Text1",
Source = "Output",
},
},
ViewInfo = OperatorInfo { Pos = { 440, 82.5 } },
},
Shake1 = Shake {
CtrlWZoom = false,
Inputs = {
Smoothness = Input { Value = 16.93, },
XMinimum = Input { Value = 0.378, },
XMaximum = Input { Value = 0.528, },
},
}
}
}

Notice that the condition is inverted. So we get true if MB is off.

This will only update if the node recooks, so as soon as you hit play.

We can use the same technique for the HiQ and this where I can demonstrate the difference. I use the same setup with the Rays tool as before. I only append a Tracker tool.

Text+, Rays and Tracker tool

To ask the node if HiQ was requested we can type in this:

iif(req:IsQuick(), 0, 1)
Expression to disable Rays tool

Now view the Tracker tool and modify the trackers position. You will find that even though HiQ is off in the Button, the Rays tool will still act as if it was activated. And this is because the Tracker will force all upstream tools to work in HiQ mode while it is tracking.

This makes sense, why should it try to track something with a worse quality only because you forgot to enable HiQ. Why is this distinction important? You probably won’t every track footage after you have applied effects. Usually, you pipe the original footage, maybe with a little increased contrast, directly into the Tracker. But for the rare case that you might need this information, here it was.

Why iif() not if()?

This is a question that I see often and this distinction cost me hours before I finally wrote iif() instead of if() by default. But at least the answer makes sense.

The Expression-field always expects a return value, otherwise, what should it do? An if statement doesn’t actually return anything though. This is why iif() was created for convenience. If we manually specify a return we can use the standard Lua if() statement.

We can write this:

:if time > 10 then return 1 else return 0 end

This works exactly like iif() it simply takes longer to write. We need the : to make clear that we are breaking out of the bounds of simple Expressions and are using Lua, and from then on we simply use the normal Lua if statement. Remember to add the return and end functions, otherwise it won’t work.

Sometimes I actually prefer to use this method, simply behause it’s easier to spot a mistake as there are no brackets or comma.

{
Tools = ordered() {
Text1_1 = TextPlus {
Inputs = {
GlobalIn = Input { Value = 1, },
Width = Input { Value = 1920, },
Height = Input { Value = 1080, },
[“Gamut.SLogVersion”] = Input { Value = FuID { “SLog2” }, },
StyledText = Input { Value = “iif(time<10, 1, 0)”, },
Font = Input { Value = “Open Sans”, },
Style = Input { Value = “Bold”, },
VerticalJustificationNew = Input { Value = 3, },
HorizontalJustificationNew = Input { Value = 3, },
ManualFontKerningPlacement = Input {
Value = StyledText {
Array = {
},
Value = “”
},
},
},
ViewInfo = OperatorInfo { Pos = { 825, 82.5 } },
},
Dissolve1 = Dissolve {
Transitions = {
[0] = “DFTDissolve”
},
Inputs = {
Mix = Input {
Value = 0,
Expression = “iif(time<10, 1, 0)”,
},
Background = Input {
SourceOp = “Background1”,
Source = “Output”,
},
Foreground = Input {
SourceOp = “Text1_1”,
Source = “Output”,
},
},
ViewInfo = OperatorInfo { Pos = { 825, 247.5 } },
},
Background1 = Background {
Inputs = {
GlobalIn = Input { Value = 1, },
Width = Input { Value = 1920, },
Height = Input { Value = 1080, },
[“Gamut.SLogVersion”] = Input { Value = FuID { “SLog2” }, },
TopLeftAlpha = Input { Value = 0, },
},
ViewInfo = OperatorInfo { Pos = { 660, 247.5 } },
},
Text1_2 = TextPlus {
Inputs = {
GlobalIn = Input { Value = 1, },
Width = Input { Value = 1920, },
Height = Input { Value = 1080, },
[“Gamut.SLogVersion”] = Input { Value = FuID { “SLog2” }, },
StyledText = Input { Value = “:if time > 10 then return 1 else return 0 end”, },
Font = Input { Value = “Open Sans”, },
Style = Input { Value = “Bold”, },
Size = Input { Value = 0.0472, },
VerticalJustificationNew = Input { Value = 3, },
HorizontalJustificationNew = Input { Value = 3, },
ManualFontKerningPlacement = Input {
Value = StyledText {
Array = {
},
Value = “”
},
},
},
ViewInfo = OperatorInfo { Pos = { 935, 82.5 } },
},
Dissolve2 = Dissolve {
Transitions = {
[0] = “DFTDissolve”
},
CtrlWZoom = false,
Inputs = {
Mix = Input { Expression = “:if time > 10 then return 1 else return 0 end”, },
Background = Input {
SourceOp = “Dissolve1”,
Source = “Output”,
},
Foreground = Input {
SourceOp = “Text1_2”,
Source = “Output”,
},
},
ViewInfo = OperatorInfo { Pos = { 935, 247.5 } },
}
}
}

Useful Expressions for automation

Get Value from a different time

We already know about using one control to drive the other, but what if you need the value at a certain time, or a frame before?

We will use the Tool:GetValue("Control", Frame) function. So to get the Position of a Transform tool at a certain time we write this in the Center Input of a second Transform.

Transform1:GetValue("Center", time-5)

What we get here is the position 5 frames prior. Kind of like a Duplicate tool.

Fusion get value from different time

If you need a value from the same tool you can use self:GetValue("Control", time) instead.

And to get only one position, like X, or the value of user inputs, you can use this syntax self:GetValue("Style", 1).Value

{ Tools = ordered() { Ellipse1 = EllipseMask { Inputs = { Filter = Input { Value = FuID { “Fast Gaussian” }, }, MaskWidth = Input { Value = 1920, }, MaskHeight = Input { Value = 1080, }, PixelAspect = Input { Value = { 1, 1 }, }, ClippingMode = Input { Value = FuID { “None” }, }, Width = Input { Value = 0.1195580835463, }, Height = Input { Value = 0.1195580835463, }, }, ViewInfo = OperatorInfo { Pos = { 385, 49.5 } }, }, Note3 = Note { Inputs = { Comments = Input { Value = “Get Value from own Input\n”, } }, ViewInfo = StickyNoteInfo { Pos = { 440, 214.5 }, Flags = { Expanded = true }, Size = { 214.994, 62.5218 } }, }, Note1 = Note { Inputs = { Comments = Input { Value = “Get Value at a certain time”, } }, ViewInfo = StickyNoteInfo { Pos = { 440, -49.5 }, Flags = { Expanded = true }, Size = { 182.592, 58.4589 } }, }, Ellipse1_1 = EllipseMask { Inputs = { Filter = Input { Value = FuID { “Fast Gaussian” }, }, MaskWidth = Input { Value = 1920, }, MaskHeight = Input { Value = 1080, }, PixelAspect = Input { Value = { 1, 1 }, }, ClippingMode = Input { Value = FuID { “None” }, }, Width = Input { Value = 0.1195580835463, }, Height = Input { Value = 0.1195580835463, }, }, ViewInfo = OperatorInfo { Pos = { 440, 313.5 } }, }, Transform1 = Transform { Inputs = { Center = Input { SourceOp = “Shake1”, Source = “Position”, }, Input = Input { SourceOp = “Ellipse1”, Source = “Mask”, }, }, ViewInfo = OperatorInfo { Pos = { 495, 49.5 } }, }, Shake1 = Shake { CtrlWZoom = false, }, Transform2 = Transform { NameSet = true, Inputs = { Center = Input { Value = { 0.44239032664978, 0.737464275032807 }, Expression = “Transform1:GetValue(\”Center\”, time-5)”, }, Input = Input { SourceOp = “Ellipse1”, Source = “Mask”, }, }, ViewInfo = OperatorInfo { Pos = { 495, 115.5 } }, }, Transform1_1 = Transform { Inputs = { Center = Input { Value = { 0.263796478135646, 0.5 }, Expression = “self:GetValue(\”Pivot\”, 20)”, }, Pivot = Input { SourceOp = “Path1”, Source = “Position”, }, Input = Input { SourceOp = “Ellipse1_1”, Source = “Mask”, }, }, ViewInfo = OperatorInfo { Pos = { 550, 313.5 } }, }, Path1 = PolyPath { DrawMode = “InsertAndModify”, CtrlWZoom = false, Inputs = { Displacement = Input { SourceOp = “Path1Displacement”, Source = “Value”, }, PolyLine = Input { Value = Polyline { Points = { { Linear = true, LockY = true, X = 0, Y = 0, RX = -0.0883333333333333, RY = 0 }, { Linear = true, LockY = true, X = -0.265, Y = 0, LX = 0.0883333333333333, LY = 0, RX = 0.147333333333333, RY = 0 }, { Linear = true, LockY = true, X = 0.177, Y = 0, LX = -0.147333333333333, LY = 0 } } }, }, }, }, Path1Displacement = BezierSpline { SplineColor = { Red = 255, Green = 0, Blue = 255 }, NameSet = true, KeyFrames = { [1] = { 0, RH = { 8.33333301574579, 0 }, Flags = { LockedY = true } }, [23] = { 0.374823196605375, LH = { 15.6674006114831, 0.304721855770353 }, RH = { 50.6263701140304, 0.638937624892366 }, Flags = { LockedY = true } }, [106] = { 1, LH = { 78.3333352504071, 1 }, Flags = { LockedY = true } } } }, Merge1 = Merge { Inputs = { Background = Input { SourceOp = “Transform2”, Source = “Output”, }, Foreground = Input { SourceOp = “Transform1”, Source = “Output”, }, PerformDepthMerge = Input { Value = 0, }, }, ViewInfo = OperatorInfo { Pos = { 605, 115.5 } }, }, Note4 = Note { Inputs = { Comments = Input { Value = “Get Value from only one Position and Text”, } }, ViewInfo = StickyNoteInfo { Pos = { 440, 445.5 }, Flags = { Expanded = true }, Size = { 228.402, 67.6005 } }, }, Value = TextPlus { CtrlWZoom = false, NameSet = true, Inputs = { GlobalIn = Input { Value = 1, }, Width = Input { Value = 1920, }, Height = Input { Value = 1080, }, [“Gamut.SLogVersion”] = Input { Value = FuID { “SLog2” }, }, StyledText = Input { Value = “Light Italic”, Expression = “Text(self:GetValue(\”Style\”, 5).Value)”, }, Font = Input { SourceOp = “ValueFont”, Source = “Value”, }, Style = Input { SourceOp = “ValueStyle”, Source = “Value”, }, VerticalJustificationNew = Input { Value = 3, }, HorizontalJustificationNew = Input { Value = 3, }, ManualFontKerningPlacement = Input { Value = StyledText { Array = { }, Value = “” }, }, }, ViewInfo = OperatorInfo { Pos = { 550, 577.5 } }, }, ValueFont = BezierSpline { SplineColor = { Red = 68, Green = 167, Blue = 244 }, NameSet = true, KeyFrames = { [1] = { 0, Flags = { Linear = true, LockedY = true }, Value = Text { Value = “Open Sans” } } } }, ValueStyle = BezierSpline { SplineColor = { Red = 193, Green = 252, Blue = 43 }, NameSet = true, KeyFrames = { [1] = { 0, RH = { 2, 0.333333333333333 }, Flags = { Linear = true, LockedY = true }, Value = Text { Value = “Bold” } }, [4] = { 1, LH = { 3, 0.666666666666667 }, RH = { 4.33333333333333, 1.33333333333333 }, Flags = { Linear = true, LockedY = true }, Value = Text { Value = “Extrabold” } }, [5] = { 2, LH = { 4.66666666666667, 1.66666666666667 }, Flags = { Linear = true, LockedY = true }, Value = Text { Value = “Light Italic” } } } }, OnlyX = TextPlus { NameSet = true, Inputs = { GlobalIn = Input { Value = 1, }, Width = Input { Value = 1920, }, Height = Input { Value = 1080, }, [“Gamut.SLogVersion”] = Input { Value = FuID { “SLog2” }, }, Center = Input { SourceOp = “Path2”, Source = “Position”, }, StyledText = Input { Value = “0.6035”, Expression = “Text(self:GetValue(\”Center\”, time+20).X)”, }, Font = Input { Value = “Open Sans”, }, Style = Input { Value = “Bold”, }, VerticalJustificationNew = Input { Value = 3, }, HorizontalJustificationNew = Input { Value = 3, }, ManualFontKerningPlacement = Input { Value = StyledText { Array = { }, Value = “” }, }, }, ViewInfo = OperatorInfo { Pos = { 440, 577.5 } }, }, Path2 = PolyPath { DrawMode = “InsertAndModify”, CtrlWZoom = false, Inputs = { Displacement = Input { SourceOp = “Path2Displacement”, Source = “Value”, }, PolyLine = Input { Value = Polyline { Points = { { Linear = true, LockY = true, X = 0, Y = 0, RX = 0.069, RY = 0 }, { Linear = true, LockY = true, X = 0.207, Y = 0, LX = -0.069, LY = 0 } } }, }, }, }, Path2Displacement = BezierSpline { SplineColor = { Red = 255, Green = 0, Blue = 255 }, NameSet = true, KeyFrames = { [1] = { 0, RH = { 14.3333333333333, 0.333333333333333 }, Flags = { Linear = true, LockedY = true } }, [41] = { 1, LH = { 27.6666666666667, 0.666666666666667 }, Flags = { Linear = true, LockedY = true } } } } } }
Get the resolution of a tool

This next expression is very useful! You can use it to create Proxy scales for a Macro, or to set several tools to dynamically switch resolutions. This can also be used to force the correct resolution. For example, a recent project for an exhibition required me to animate paintings that were scanned in enormous resolutions.

Usually, when you create a mask, Fusion will automatically set the mask to the correct resolution of the image, but this doesn’t happen if you’re not using the Mask input of a tool but the Matte Control. After several times of having my mask resolutions change to the project resolution and messing up my masks, I set all my masks to reference the output resolution of a tool. Now I was able to change the resolution of my images AND have all masks update correctly.

The Expression works like this:

Tool.Output.Width
Tool.Output.Heigth

So in my case I’ve used a Background tool an animated the Width to demonstrate this:

Fusion updating resolutions
{ Tools = ordered() { Note2 = Note { Inputs = { Comments = Input { Value = “Automatically get and set resolution. Handy to keep masks correct.”, } }, ViewInfo = StickyNoteInfo { Pos = { 1045, -148.5 }, Flags = { Expanded = true }, Size = { 171.419, 79.7894 } }, }, Normal_Mask = RectangleMask { NameSet = true, Inputs = { Filter = Input { Value = FuID { “Fast Gaussian” }, }, MaskWidth = Input { Value = 1920, }, MaskHeight = Input { Value = 1080, }, PixelAspect = Input { Value = { 1, 1 }, }, ClippingMode = Input { Value = FuID { “None” }, }, Width = Input { Value = 1, }, }, ViewInfo = OperatorInfo { Pos = { 1100, -16.5 } }, }, Background1 = Background { Inputs = { GlobalIn = Input { Value = 1, }, Width = Input { SourceOp = “Background1Width”, Source = “Value”, }, Height = Input { Value = 1080, }, [“Gamut.SLogVersion”] = Input { Value = FuID { “SLog2” }, }, Type = Input { Value = FuID { “Corner” }, }, TopLeftRed = Input { Value = 1, }, TopRightGreen = Input { Value = 1, }, BottomLeftBlue = Input { Value = 1, }, BottomRightGreen = Input { Value = 1, }, BottomRightBlue = Input { Value = 1, }, }, ViewInfo = OperatorInfo { Pos = { 990, 49.5 } }, }, Background1Width = BezierSpline { SplineColor = { Red = 225, Green = 255, Blue = 0 }, NameSet = true, KeyFrames = { [1] = { 1920, RH = { 14, 2118.66666666667 }, Flags = { Linear = true } }, [40] = { 2516, LH = { 27, 2317.33333333333 }, Flags = { Linear = true } } } }, MatteControl1 = MatteControl { Inputs = { MatteCombine = Input { Value = 4, }, Filter = Input { Value = FuID { “Fast Gaussian” }, }, PostMultiplyImage = Input { Value = 1, }, Background = Input { SourceOp = “Background1”, Source = “Output”, }, Foreground = Input { SourceOp = “Normal_Mask”, Source = “Mask”, }, }, ViewInfo = OperatorInfo { Pos = { 1155, 49.5 } }, }, MatteControl1_1 = MatteControl { Inputs = { MatteCombine = Input { Value = 4, }, Filter = Input { Value = FuID { “Fast Gaussian” }, }, PostMultiplyImage = Input { Value = 1, }, Background = Input { SourceOp = “Background1”, Source = “Output”, }, Foreground = Input { SourceOp = “Updating_Mask”, Source = “Mask”, }, }, ViewInfo = OperatorInfo { Pos = { 1155, 115.5 } }, }, Updating_Mask = RectangleMask { CtrlWZoom = false, NameSet = true, Inputs = { Filter = Input { Value = FuID { “Fast Gaussian” }, }, OutputSize = Input { Value = FuID { “Custom” }, }, MaskWidth = Input { Value = 1920, Expression = “Background1.Output.Width”, }, MaskHeight = Input { Value = 1080, Expression = “Background1.Output.Height”, }, PixelAspect = Input { Value = { 1, 1 }, }, ClippingMode = Input { Value = FuID { “None” }, }, Width = Input { Value = 1, }, }, ViewInfo = OperatorInfo { Pos = { 1100, 181.5 } }, } } }

Table of Expressions from this Page

Some of the states that you can ask the Buttons/Fields in the Playbar in Fusion and other Expressions we discussed on this page:

comp.HiQreturns true if HiQ-Button is activated
comp.Proxyreturns true if Proxy-Button is activated
comp.ProxyScalereturns the number by which the original resolution was divided by
comp.RenderStartreturns the Render Start frame
comp.RenderEndreturns the Render End frame
comp.CurrentTimereturns the current frame number
comp.GlobalStartreturns the global composition start
comp.GlobalEndreturns the global composition end
req:IsQuick()returns true if the node does not request a HiQ-Mode
req:IsNoMotionBlur()returns true if the node does not request Motion blur
Tool:GetValue("Control", Frame)returns the value at a specific time
Tool.Output.Widthreturns the resolution width of a tool
Tool.Output.Heigthreturns the resolution height of a tool

On the next page we will look at some Math operations.

Quickly share this!

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
Scroll to top
0
Would love your thoughts, please comment.x