Jump to: Board index » General » Fusion

Expressions run on first frame only

Learn about 3D compositing, animation, broadcast design and VFX workflows.
  • Author
  • Message
Offline

henit1

  • Posts: 12
  • Joined: Mon Jan 29, 2024 12:57 pm
  • Real Name: Henrik Haugberg

Expressions run on first frame only

PostFri Feb 09, 2024 6:03 pm

Hi Resolvers. When I have a node in a fusion composition that does some calculations in expressions (like a calculating center, width and height based on user controls), values that will not change while the clip is running. Is there any way to make the expressions run only on the first frame, but have their values available for other nodes to use (reference in expressions) in the whole clip?
Offline

csx333

  • Posts: 75
  • Joined: Thu Sep 26, 2019 10:15 am
  • Location: Germany
  • Real Name: Christoph Schmid

Re: Expressions run on first frame only

PostSun Feb 11, 2024 3:03 pm

You can use iif :

iif(time==0, "do this", "else this")

syntax:
iif(Condition is true, return this, else this)
_____________________________________
Davinci Resolve Studio 18.6.5
Windows 10 Pro 22H2
Linux Ubuntu Studio 23.10
GeForce RTX 2070 Super
AMD Ryzen 9 3900X
32 GB DDR4
Offline

henit1

  • Posts: 12
  • Joined: Mon Jan 29, 2024 12:57 pm
  • Real Name: Henrik Haugberg

Re: Expressions run on first frame only

PostMon Feb 12, 2024 7:32 am

csx333 wrote:You can use iif :

iif(time==0, "do this", "else this")

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


Thank you for your response. Is it then possible to set the value on that control at that first frame, and return the value that calculation produced at that first frame on the other frames? Would something like this work (for the Width control)? Or will it lead to some kind of endless loop, since it is referencing itself?

Code: Select all
iif(time == 0, CALCULATION-HERE, Width)


EDIT:
I tried referencing itself this way, on a Center point. It gets the correct value on the first frame, but then return to Point(0, 0) on the other frames where it references itself :-/
Offline

csx333

  • Posts: 75
  • Joined: Thu Sep 26, 2019 10:15 am
  • Location: Germany
  • Real Name: Christoph Schmid

Re: Expressions run on first frame only

PostMon Feb 12, 2024 9:06 am

I'm sorry, but I don't understand what you are trying to achieve. Please be more specific.
_____________________________________
Davinci Resolve Studio 18.6.5
Windows 10 Pro 22H2
Linux Ubuntu Studio 23.10
GeForce RTX 2070 Super
AMD Ryzen 9 3900X
32 GB DDR4
Offline

Hendrik Proosa

  • Posts: 3057
  • Joined: Wed Aug 22, 2012 6:53 am
  • Location: Estonia

Re: Expressions run on first frame only

PostMon Feb 12, 2024 12:46 pm

If I understand correctly you want the expression to evaluate to same result as first frame produces, on every frame. In that case you would need to sample/evaluate the input variables at that specific frame. I think it is possible, but I don't know the exact syntax for it.
I do stuff
Offline

henit1

  • Posts: 12
  • Joined: Mon Jan 29, 2024 12:57 pm
  • Real Name: Henrik Haugberg

Re: Expressions run on first frame only

PostMon Feb 12, 2024 1:00 pm

Sorry about the confusing question, here is an attempt to clarify:

I need to place several elements on the screen, like rectangles or points to create a kind of graph/visualization. To simplify the actual case behind this, think of putting 50 rectangle poly shapes inside the video window. However, the placement and width/height of those boxes, require calculation to be placed in the manner I need. This to avoid having to re-calculate this manually all the time. So I have some source data, that is values put in several user controls (numbers) and expressions that use these values to calculate the width, height and center point of each box. This works well, however when I have 50 of these, calculating all four values (width, height and center x/y) in expressions that way, running the composition become REALLY slow. Playing the video in the preview window in the edit page to be able to place keyframes and other work I while editing goes from 30 frames per second down to below 3, some times stopping entirely. Rendering in the delivery page become really slow too, but that is possible to live with. Editing a video with these graphics on top is a bigger problem.

If I place the calculations on a separate node for each box, and copy the values they produce (width, height and center x/y) over to the actual node that is used to render the boxes on screen, the preview runs smoothly at 30fps and delivery render runs fast, but then I have to manually copy over these 4 values for every one of these 50 boxes (200 copy-paste values, even more in the real case this example is based on) every time I change something in the source data, making it very impractical and time consuming adjusting things to get the desired end result.

But since the four values does not change (the elements remain in the same place on the screen through the clip), I was hoping it was possible to make Fusion run these apparently very expensive expressions just one time on the first frame, and then reuse the produced values "statically", so I can adjust the source values, and see the result without having to copy over the four values manually, and not having the drop in performance because the expressions was just performed once per copy of the composition clip in the timeline instead of once per box per frame (which seems to be the cause of the extreme drop in performance)
Offline

csx333

  • Posts: 75
  • Joined: Thu Sep 26, 2019 10:15 am
  • Location: Germany
  • Real Name: Christoph Schmid

Re: Expressions run on first frame only

PostMon Feb 12, 2024 1:14 pm

To get the value of a specific time you could use the GetValue() method.

Syntax:

Control:GetValue("Parameter", Time)

For example:
Code: Select all
Rectangle1:GetValue("Center", 20)

will get the Value of Rectangle1.Center at frame 20
Code: Select all
Rectangle1:GetValue("Center", time-10).X

will get the X-Value of Rectangle1.Center 10 frames ago.
_____________________________________
Davinci Resolve Studio 18.6.5
Windows 10 Pro 22H2
Linux Ubuntu Studio 23.10
GeForce RTX 2070 Super
AMD Ryzen 9 3900X
32 GB DDR4
Offline

csx333

  • Posts: 75
  • Joined: Thu Sep 26, 2019 10:15 am
  • Location: Germany
  • Real Name: Christoph Schmid

Re: Expressions run on first frame only

PostMon Feb 12, 2024 1:27 pm

Sorry, when I wrote my post I didn't see that you had posted your explanation.

Maybe you could create some fake controls to do the calculation once and
"save" the results as control values ?
_____________________________________
Davinci Resolve Studio 18.6.5
Windows 10 Pro 22H2
Linux Ubuntu Studio 23.10
GeForce RTX 2070 Super
AMD Ryzen 9 3900X
32 GB DDR4
Offline

henit1

  • Posts: 12
  • Joined: Mon Jan 29, 2024 12:57 pm
  • Real Name: Henrik Haugberg

Re: Expressions run on first frame only

PostMon Feb 12, 2024 1:34 pm

csx333 wrote:Sorry, when I wrote my post I didn't see you posted your explanation.

Maybe you could create some fake controls to do the calculation once and
"save" the results as control values ?


I tried doing the calculations on a separate node, and on the node that needs to use them (the element on the screen), I just reference the value that has the calculation expression in the source node, something like:

CalcNode
- Center: { Expression = "THE-CALCULATION" }

DisplayNode
- Center: { Expression = "CalcNode.Center" }

but then it seems the display node attempt to get the value from the source node on every frame, triggering the calculation to run on every frame too, leading to just as bad performance. I have tried using node instances and a few other things, but the only thing I have found that works without getting the bad performance, is the time consuming solution of copy-pasting the calculated values of every single one of the nodes every time they are changed, so the values on the elements being rendered in the video window does not have any calculation.

I wish there was a sort of "static" checkbox in controls, similar to Animatable and Passive, telling resolve to only run the expression once
Offline

birdseye

  • Posts: 361
  • Joined: Fri Jun 12, 2020 2:36 pm
  • Real Name: Iain Fisher

Re: Expressions run on first frame only

PostMon Feb 12, 2024 1:56 pm

If you post an example of what you have so far, perhaps someone will be able to refine what you have.
Offline

csx333

  • Posts: 75
  • Joined: Thu Sep 26, 2019 10:15 am
  • Location: Germany
  • Real Name: Christoph Schmid

Re: Expressions run on first frame only

PostMon Feb 12, 2024 2:00 pm

I haven't tested but maybe you can do something like this:

calculation Node:
iif(time==0, "do your calculations", 0)
this will only calculate at first frame (i hope) otherwise the value 0 is taken

displayed Node:
calculationNode:GetValue("Width", 0)
this will take the value of the calculation node at frame 1


Edit: Sorry, just seen there was a typo... it's not "iff" it's "iif"
_____________________________________
Davinci Resolve Studio 18.6.5
Windows 10 Pro 22H2
Linux Ubuntu Studio 23.10
GeForce RTX 2070 Super
AMD Ryzen 9 3900X
32 GB DDR4
Offline
User avatar

Bryan Ray

  • Posts: 2491
  • Joined: Mon Nov 28, 2016 5:32 am
  • Location: Los Angeles, CA, USA

Re: Expressions run on first frame only

PostMon Feb 12, 2024 5:59 pm

It sounds like what you need to do is to remove the calculations to a script that you run manually one time to initialize the layout. So you'd set your parameters up, click a button that runs the script, and then get on with your work. No live expressions, and so no per-frame recalculation.

The following demonstrates how to set up a button control with an embedded script. This one creates a Loader pointing to the file rendered by a Saver node:

Code: Select all
{
    Tools = ordered() {
        Saver1 = Saver {
            CtrlWZoom = false,
            Inputs = {
                ProcessWhenBlendIs00 = Input { Value = 0, },
                Clip = Input {
                    Value = Clip {
                        Length = 0,
                        Saving = true,
                        TrimIn = 0,
                        ExtendFirst = 0,
                        ExtendLast = 0,
                        Loop = 1,
                        AspectMode = 1,
                        Depth = 1,
                        GlobalStart = -2000000000,
                        GlobalEnd = 0,
                    },
                },
                OutputFormat = Input { Value = FuID { "TargaFormat", }, },
                ["Gamut.SLogVersion"] = Input { Value = FuID { "SLog2", }, },
            },
            ViewInfo = OperatorInfo { Pos = { 495, 82.5, }, },
            UserControls = ordered() {
                MakeLoader = {
                    ICS_ControlPage = "File",
                    INPID_InputControl = "ButtonControl",
                    LINKS_Name = "Make Loader",
                    BTNCS_Execute = [[
                        comp:Lock()
                        flow = comp.CurrentFrame.FlowView
                        posx, posy = flow:GetPos(tool)
                        filepath = tool.Clip[1]
                        myloader = comp:AddTool("Loader", posx+1, posy - 1)
                        myloader.Clip = filepath
                       
                        -- parse file name
                        pathtable = eyeon.split(filepath, "\\")
                        -- find last index of table
                        k = 0
                        for i in ipairs(pathtable) do
                            k = i
                        end
                        filename = pathtable[k]
                        j,k = string.find(filename, "_v")
                        if k then
                            l = string.find(filename, "%.", k+1)
                            version = string.sub(filename, k, l-1)
                            filename = string.sub(filename, 1, j-1)
                                               
                            myloader:SetAttrs({TOOLS_Name = version.."_"..filename, TOOLB_NameSet = true})
                        end
                        comp:Unlock()
                    ]],
                },
            },
        },
    },
    ActiveTool = "Saver1",
}


It's simplest to create the button using the Add Controls dialog in the UI, then copy the node to a programmer's text editor (Sublime, Notepad++, etc) and insert the script there. Then you can copy that back into the Nodes view to test it.

Just be aware that copying back out of Fusion again will mangle the script; it will still work, but it'll be difficult to work with due to bad formatting
Bryan Ray
http://www.bryanray.name
http://www.sidefx.com
Offline

henit1

  • Posts: 12
  • Joined: Mon Jan 29, 2024 12:57 pm
  • Real Name: Henrik Haugberg

Re: Expressions run on first frame only

PostTue Feb 13, 2024 6:28 am

Bryan Ray wrote:It sounds like what you need to do is to remove the calculations to a script ...


I can look into that solution. This suggestion also got me thinking. Can a script like that set values on controls? Because if "CalculationNode" does the calculation, and "DisplayNode" has no expressions, but need those calculated values, maybe a script could just go through the different nodes and copy the calculated control values from CalculationNode over to the values on DisplayNode? Unless scripts are not allowed to set control values.
Offline

henit1

  • Posts: 12
  • Joined: Mon Jan 29, 2024 12:57 pm
  • Real Name: Henrik Haugberg

Re: Expressions run on first frame only

PostTue Feb 13, 2024 1:54 pm

birdseye wrote:If you post an example of what you have so far, perhaps someone will be able to refine what you have.


Here are two simplified examples. They only multiply two numbers in the width and height values on each rectangle node, and set a point on the center value in an expression instead of just directly without expression. Those simple calculations on 50 copies of the node, leads to playback down from 30 fps to 7 fps on my computer:

settings-files.zip
(6.14 KiB) Downloaded 38 times


Screenshots of playing the clips in the preview window (look at the fps above):
Screenshot 2024-02-13 at 14.38.45.png
Screenshot 2024-02-13 at 14.38.45.png (209.02 KiB) Viewed 1275 times

Screenshot 2024-02-13 at 14.39.00.png
Screenshot 2024-02-13 at 14.39.00.png (207.34 KiB) Viewed 1275 times


The actual case this is based on has more complex calculations of the values, including referencing a few different values both on the same node and on a common node for values that are the same in all the nodes calculating this way (like "constants"). And the real-world-cases have 100+ items (compared to 50 here) with more than three nodes per element, leading to much slower performance than with 7fps from this example, but with a variant of it that does not make the calculations (because I have copied the values over from a calculating unconnected node manually for every single node and value) it still runs at 24fps without any problem.
Offline
User avatar

Bryan Ray

  • Posts: 2491
  • Joined: Mon Nov 28, 2016 5:32 am
  • Location: Los Angeles, CA, USA

Re: Expressions run on first frame only

PostTue Feb 13, 2024 9:52 pm

henit1 wrote:
Bryan Ray wrote:It sounds like what you need to do is to remove the calculations to a script ...


I can look into that solution. This suggestion also got me thinking. Can a script like that set values on controls?


Absolutely! In the example I gave above, you'll see these lines:
filepath = tool.Clip[1]
myloader = comp:AddTool("Loader", posx+1, posy - 1)
myloader.Clip = filepath

The first queries the current tool for the value contained in it's Clip control. In the case of a script run from a button script, or a tool script run by right-clicking a tool and choosing Script > ..., "tool" will always be a handle to the tool the script is being run on.

The second line creates a new Loader node and assigns a handle to the variable myloader.

The third line refers to the Clip input on the new Loader. A simple assignment puts the string we got from the first line into that input.

The tricky bit when the script itself is not creating the nodes you want to manipulate is that you need to refer to them as members of the composite object. That is, if you have a Merge node named Merge3, and you want to set its Blend control to 0.5, this is the command:

comp.Merge3.Blend = 0.5

If you want to read an input, though, you need to also indicate which frame to get the value from, since the script doesn't know anything about time, like so:

myBlendValue = comp.Merge3.Blend[comp.CurrentTime]

If the value doesn't change, like the Clip above, it's safe to enter any integer, or you can use fusion.TIME_UNDEFINED. Or you can pull the value from a specific frame by entering that frame number in the brackets.

Combining these ideas, if you want to multiply two Transform nodes' Size values and store the result in a third:

comp.Transform1.Size = comp.Transform2.Size[1] * comp.Transform3.Size[1]
Bryan Ray
http://www.bryanray.name
http://www.sidefx.com
Offline

henit1

  • Posts: 12
  • Joined: Mon Jan 29, 2024 12:57 pm
  • Real Name: Henrik Haugberg

Re: Expressions run on first frame only

PostWed Feb 14, 2024 7:20 am

Bryan Ray wrote:Absolutely! In the example I gave above, you'll see these lines (...)


Is there a different way to do this inside expressions? Or limitations to what can be set? I created one "CalcNode" and one "DisplayNode", made a calculation in the expression on the first and try to set it on the second as part of the expression like this:
Code: Select all
: comp.DisplayNode.Width = time * 0.01; return time * 0.01

A bit clunky, I know, just trying to see what works. But that makes the node red and give this in the console:
Code: Select all
CalcNode cannot get Parameter for Width at time 105
CalcNode failed at time 105

Maybe a Start Render Script on the calcnode is better? My hope is that the calc node can just make it's calculations (minimum) one time, set the result values on the display node, and then it can render with that value in every frame without any expensive expression to fetch those values so I gain the "automation" in the calc node running the expressions (avoiding copy-pasting values every time they change) and gaining the good performance.
Offline
User avatar

Bryan Ray

  • Posts: 2491
  • Joined: Mon Nov 28, 2016 5:32 am
  • Location: Los Angeles, CA, USA

Re: Expressions run on first frame only

PostThu Feb 15, 2024 6:49 am

I don't think it's possible to set a different input from a simple expression. They only have write permission for the input they're controlling. Also, I think your goal is to avoid expressions since by their nature they have to evaluate on every frame and cannot be cached.

The Start Render script could do the job, but it would only run when you actually start a render -- it won't do anything while you're interactive, which makes setting things up difficult. You'd have to start and stop a render to get it to set values, and then start working.

The Frame Render script would work for interactivity, but it suffers the same problem as an expression: it runs on every frame and is therefore not optimized. And besides that, I find those scripts to be somewhat flaky. But it's possible I never learned to use them effectively.
Bryan Ray
http://www.bryanray.name
http://www.sidefx.com
Offline

henit1

  • Posts: 12
  • Joined: Mon Jan 29, 2024 12:57 pm
  • Real Name: Henrik Haugberg

Re: Expressions run on first frame only

PostThu Feb 15, 2024 7:10 am

Bryan Ray wrote:I don't think it's possible to set a different input...

Thank you.

Btw, side question. If you have a node with an input (like Mask or Input), but you don't know the name of the node connected there. Such as for an input inside a macro that compositions using the macro can connect to. Is it possible then to fetch values like Width, Center og custom controls from the connected node? I have tried referencing in expressions something like "EffectMask.MyUserControl", but that does not work. Is there another way to access them in those cases?
Offline
User avatar

Bryan Ray

  • Posts: 2491
  • Joined: Mon Nov 28, 2016 5:32 am
  • Location: Los Angeles, CA, USA

Re: Expressions run on first frame only

PostThu Feb 15, 2024 7:00 pm

Not that I've ever been able to find. In a full script, you can get, for instance, the Center input of a connected node like this:

comp.toolName.Input:GetConnectedOutput():GetTool().Center

Simple expressions don't have the ability to access anything outside of themselves, though. In fact, if you try to access even the tool's own inputs, instead of getting an Input Lua object, which looks like this:
Input (0x00000000423D6B00) [App: 'Fusion' on 127.0.0.1, UUID: e2c31ac2-0ac9-4ebc-80e4-e4d8ee36c6c7]

you get some kind of low-level code object like this:
cdata<struct Image *>: 0x122a10c0

It's possible there's something in that struct that could be pulled out for more information, but it's completely opaque, with no way I know of to find out what's inside it, other than a few bits that have been previously documented, like the DataWindow and Metadata tables.
Bryan Ray
http://www.bryanray.name
http://www.sidefx.com

Return to Fusion

Who is online

Users browsing this forum: sbolinger and 44 guests