Jump to: Board index » General » Fusion

Auto Position using Expression

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

DavySilva

  • Posts: 183
  • Joined: Thu Mar 03, 2022 12:36 pm
  • Location: UK and Ireland, sometimes EU.
  • Real Name: Davy Silva

Auto Position using Expression

PostWed Jun 15, 2022 10:12 am

Hi all,

First of all, sorry if there's a topic talking about it. I couldn't find it.

I'm looking to add an expression where a node automatically gets its vertical position from another node.

Example: A picture gets its position under another picture and I can add a Math to determine the gap in btw.

Is that possible using Expression?
Online Editor and Colourist.
“Never stop learning because life never stops teaching”
Offline

xunile

  • Posts: 3075
  • Joined: Mon Apr 23, 2018 5:21 am
  • Real Name: Eric Eisenmann

Re: Auto Position using Expression

PostWed Jun 15, 2022 6:46 pm

Yes, it is possible using Expression.

You can add your 2 images and Merge them with a Merge node. You can add a Transform node after each of them. On the Transform you want to be controlled by the other, right-click on the Center parameter and choose Expression. Then add this expression, substituting your transform name for the one I used.

Point(Transform2.Center.X,Transform2.Center.Y + .4)

This will keep the second image .4 above the first.
Attachments
2022-06-15 (3).jpg
2022-06-15 (3).jpg (272.15 KiB) Viewed 1742 times
2022-06-15 (4).jpg
2022-06-15 (4).jpg (270.14 KiB) Viewed 1742 times
2022-06-15 (5).jpg
2022-06-15 (5).jpg (273.68 KiB) Viewed 1742 times
Win 10 Home | Intel i7 - 10700f 64 GB 1 TB GB SSD 2 TB SSD
RTX-3060 12 GB | Resolve Studio 18.6.6| Fusion Studio 18.6.6

Win 10 Home | Intel Core I7-7700HQ 32 GB 1 TB NVME SSD 1 TB SATA SSD
GTX-1060-6GB | Resolve 17.4.6
Offline

DavySilva

  • Posts: 183
  • Joined: Thu Mar 03, 2022 12:36 pm
  • Location: UK and Ireland, sometimes EU.
  • Real Name: Davy Silva

Re: Auto Position using Expression

PostWed Jun 15, 2022 9:22 pm

Thank you, Eric,

This might be something to start with. I was testing some ideas today but not sure how far I can go.

Basically, I wanted to create text nodes and automatically join them vertically, I put a crop node to find out the size of the box and I wanted to copy the Y result to the Transform node but I could not find out a way to do that. The crop gives an integer in pixels but Transform works differently and even when I change the reference think at the bottom it didn't work.

Also, I tried to create an auto-refresh for the Auto Crop property. Like every time you change the Text tab settings, it would push a new integer and reset the whole system. I will get there, just need some time to think.

This is just me messing with the software, don't need to get it done.
Online Editor and Colourist.
“Never stop learning because life never stops teaching”
Offline

Okke Verbart

  • Posts: 290
  • Joined: Tue Jan 17, 2017 8:40 pm

Re: Auto Position using Expression

PostThu Jun 16, 2022 7:22 am

Hi - re the auto crop thing. I don't know of a way to auto-refresh it (maybe via script), but an alternative is to just mimic it with expressions for the offset and size. I use the DataWindow property here. Bryan gives a very nice explanation here:

viewtopic.php?f=22&t=72710

In the comp below I added a small expression to feed different strings in the 1st 4 frames and I also added an expression to randomize the size. The magic then happens in the crop node. Display that one and then go through the 1st 4 frames: it will auto-crop:

Code: Select all
{
   Tools = ordered() {
      Text1 = TextPlus {
         Inputs = {
            Width = Input { Value = 1000, },
            Height = Input { Value = 1000, },
            ["Gamut.SLogVersion"] = Input { Value = FuID { "SLog2" }, },
            StyledText = Input {
               Value = StyledText {
                  Value = "TEXT2"
               },
               Expression = ":myarray={\"Text1\",\"String2\",\"Next One\",\"Another One\"}; return myarray[time+1];",
            },
            Font = Input { Value = "Open Sans", },
            Style = Input { Value = "Bold", },
            Size = Input {
               Value = 0.41931143481139,
               Expression = "random()",
            },
            VerticalJustificationNew = Input { Value = 3, },
            HorizontalJustificationNew = Input { Value = 3, },
         },
         ViewInfo = OperatorInfo { Pos = { 349.333, 57.6667 } },
      },
      Crop1 = Crop {
         CtrlWZoom = false,
         Inputs = {
            XOffset = Input {
               Value = -1093,
               Expression = "(Text1.Output.OriginalWidth -XSize)/2",
            },
            YOffset = Input {
               Value = 306,
               Expression = "(Text1.Output.OriginalHeight-YSize)/2",
            },
            XSize = Input {
               Value = 3186,
               Expression = "Text1.Output.DataWindow[3]-Text1.Output.DataWindow[1]",
            },
            YSize = Input {
               Value = 388,
               Expression = "Text1.Output.DataWindow[4]-Text1.Output.DataWindow[2]",
            },
            Input = Input {
               SourceOp = "Text1",
               Source = "Output",
            },
         },
         ViewInfo = OperatorInfo { Pos = { 346.667, 88.5757 } },
      }
   }
}
www.ablackbirdcalledsue.com
Offline

Sander de Regt

  • Posts: 3582
  • Joined: Thu Nov 13, 2014 10:09 pm

Re: Auto Position using Expression

PostThu Jun 16, 2022 8:25 am

The easiest way to autocrop is by putting

AutoCrop=1

in the frame render script of the crop tool and it does just that.

The downside is of course that it runs every frame, but then again, the same thing goes for expressions as well, so computationallywise it shouldn't make too much difference.
Sander de Regt

ShadowMaker SdR
The Netherlands
Offline

DavySilva

  • Posts: 183
  • Joined: Thu Mar 03, 2022 12:36 pm
  • Location: UK and Ireland, sometimes EU.
  • Real Name: Davy Silva

Re: Auto Position using Expression

PostThu Jun 16, 2022 8:57 am

Brilliant,

That is great. I was doing something similar Okke explained.

What's the best approach to copy the result over to the Transform node? I can't convert pixels to points yet.
Online Editor and Colourist.
“Never stop learning because life never stops teaching”
Offline

Sander de Regt

  • Posts: 3582
  • Joined: Thu Nov 13, 2014 10:09 pm

Re: Auto Position using Expression

PostThu Jun 16, 2022 9:05 am

I am not sure what you mean by converting pixels to points?
Sander de Regt

ShadowMaker SdR
The Netherlands
Offline

DavySilva

  • Posts: 183
  • Joined: Thu Mar 03, 2022 12:36 pm
  • Location: UK and Ireland, sometimes EU.
  • Real Name: Davy Silva

Re: Auto Position using Expression

PostThu Jun 16, 2022 9:40 am

Neither do I. :D :D :D :D

I'm just putting some ideas together.

I'll get there.
Online Editor and Colourist.
“Never stop learning because life never stops teaching”
Offline
User avatar

Bryan Ray

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

Re: Auto Position using Expression

PostThu Jun 16, 2022 4:59 pm

I had a nice post started, but then when I tried to implement it, I discovered something annoying: Even if you set the Reference Size in a Transform, as soon as you put an expression on the Point control, you're back to normalized coordinates. So you'll always need to do the conversion into and out of normalized coordinates yourself.

So let's assume that you're making a layout out of images of various sizes, and you just want to stack them vertically with a gap control. In this example, I'm just going to use some Background and Scale tools to represent the incoming images. I'll designate them A, B and C. By using Scale instead of Transform, the images and canvas get resized together, so you don't need to extract the Domain of Definition (DoD) with an auto-auto-crop.

To start, we'll Merge each image over a common Background (which I'll name Canvas) of known size (3840x2160), with the Transforms after the Merge, then Merge the whole set together at the end. I'm using the Merge over Background instead of Crops here so the entire thing can respond to the Use Frame Format settings if desired.

We can get the dimensions of the incoming images by querying the Output of the associated Scale node: ScaleA.Output.OriginalWidth and ScaleA.Output.OriginalHeight, for instance. The thing to remember is that the Transforms always measure from the center of the raster, not the lower-left corner, so when setting a position, we'll need to use half the height.

To convert from pixels to normalized coordinates, simply divide the pixel dimensions by Canvas.Output.OriginalHeight. To get a pixel distance, multiply that expression by the normalized coordinates.

I'm going to place the images with A at the top, B below it, then C below that, then center the entire composition. Since I want it centered, it's tempting to start with B and just let it stay where it is, but each item is a different height, so it may not end up actually in the center of the screen. So I'll instead start from the bottom because addition is easier on my brain than subtraction.

To place the first object at the bottom of the screen, I use this expression for the Center control of TransformC:
Point(0.5, (ScaleC.Output.OriginalHeight/2) / Canvas.Output.OriginalHeight)

Now, I can change the Scale of the element or the height of the Canvas, and it will always stick to the bottom edge. Next, element B. I want that one to stick to the top of Element C, so it gets this expression:

Point(0.5, (ScaleC.Output.OriginalHeight + ScaleB.Output.OriginalHeight/2) / Canvas.Output.OriginalHeight)

Note that I'm using the full height of element C—I need the distance from the bottom of the screen, plus half the height of element B. Element A gets the same treatment: half its height plus the full height of each object below it:

Point(0.5, (ScaleC.Output.OriginalHeight + ScaleB.Output.OriginalHeight+ ScaleA.Output.OriginalHeight/2) / Canvas.Output.OriginalHeight)

Now let's get some padding in there. For flexibility, we'll distinguish between padding between elements and the margin between the edge of the frame and the composition. This is pretty easy. All we really need is a slider to set the parameters and some simple addition in each expression. At first, I used a CustomTool for its screw controls, but they're not very responsive, so instead I'm going to use the Edit Controls feature to add the slider to the Canvas node.

We don't need padding on TransformC, but we'll add it to TransformB and twice to Transform A:

Point(0.5, (ScaleC.Output.OriginalHeight + Canvas.Padding*2 + ScaleB.Output.OriginalHeight+ ScaleA.Output.OriginalHeight/2) / Canvas.Output.OriginalHeight)

Now I'll Crop the entire composition to the new height, adding a Crop node after my last Merge. Crop operates from the lower left corner of the image (0,0), so if I leave the Offsets alone, I can calculate the total height by adding up all the elements' heights and adding the padding. Then I need only add twice the margin value (accounting for both top and bottom), then Offset Y by -Margin to arrive at the final frame.

And here's the entire setup:

Code: Select all
{
   Tools = ordered() {
      A = Background {
         NameSet = true,
         Inputs = {
            Width = Input { Value = 640, },
            Height = Input { Value = 480, },
            ["Gamut.SLogVersion"] = Input { Value = FuID { "SLog2" }, },
            TopLeftRed = Input { Value = 0.551, },
         },
         ViewInfo = OperatorInfo { Pos = { 660, -181.5 } },
      },
      ScaleA = Scale {
         NameSet = true,
         Inputs = {
            XSize = Input { Value = 1.074, },
            HiQOnly = Input { Value = 0, },
            PixelAspect = Input { Value = { 1, 1 }, },
            Input = Input {
               SourceOp = "A",
               Source = "Output",
            },
         },
         ViewInfo = OperatorInfo { Pos = { 770, -181.5 } },
      },
      ScaleB = Scale {
         NameSet = true,
         Inputs = {
            HiQOnly = Input { Value = 0, },
            PixelAspect = Input { Value = { 1, 1 }, },
            Input = Input {
               SourceOp = "B",
               Source = "Output",
            },
         },
         ViewInfo = OperatorInfo { Pos = { 770, -148.5 } },
      },
      B = Background {
         NameSet = true,
         Inputs = {
            Width = Input { Value = 290, },
            Height = Input { Value = 743, },
            ["Gamut.SLogVersion"] = Input { Value = FuID { "SLog2" }, },
            TopLeftGreen = Input { Value = 0.52, },
         },
         ViewInfo = OperatorInfo { Pos = { 660, -148.5 } },
      },
      C = Background {
         NameSet = true,
         Inputs = {
            Width = Input { Value = 839, },
            Height = Input { Value = 421, },
            ["Gamut.SLogVersion"] = Input { Value = FuID { "SLog2" }, },
            TopLeftBlue = Input { Value = 0.52, },
         },
         ViewInfo = OperatorInfo { Pos = { 660, -115.5 } },
      },
      ScaleC = Scale {
         NameSet = true,
         Inputs = {
            HiQOnly = Input { Value = 0, },
            PixelAspect = Input { Value = { 1, 1 }, },
            Input = Input {
               SourceOp = "C",
               Source = "Output",
            },
         },
         ViewInfo = OperatorInfo { Pos = { 770, -115.5 } },
      },
      Merge3 = Merge {
         Inputs = {
            Background = Input {
               SourceOp = "Canvas",
               Source = "Output",
            },
            Foreground = Input {
               SourceOp = "ScaleA",
               Source = "Output",
            },
            PerformDepthMerge = Input { Value = 0, },
         },
         ViewInfo = OperatorInfo { Pos = { 880, -181.5 } },
      },
      Merge5 = Merge {
         Inputs = {
            Background = Input {
               SourceOp = "Canvas",
               Source = "Output",
            },
            Foreground = Input {
               SourceOp = "ScaleC",
               Source = "Output",
            },
            PerformDepthMerge = Input { Value = 0, },
         },
         ViewInfo = OperatorInfo { Pos = { 880, -115.5 } },
      },
      Merge4 = Merge {
         Inputs = {
            Background = Input {
               SourceOp = "Canvas",
               Source = "Output",
            },
            Foreground = Input {
               SourceOp = "ScaleB",
               Source = "Output",
            },
            PerformDepthMerge = Input { Value = 0, },
         },
         ViewInfo = OperatorInfo { Pos = { 880, -148.5 } },
      },
      TransformA = Transform {
         NameSet = true,
         Inputs = {
            Center = Input { Expression = "Point(0.5, 0+(ScaleC.Output.OriginalHeight + Canvas.Padding*2 + ScaleB.Output.OriginalHeight+ ScaleA.Output.OriginalHeight/2) / Canvas.Output.OriginalHeight)", },
            ReferenceSize = Input { Value = 1, },
            Input = Input {
               SourceOp = "Merge3",
               Source = "Output",
            },
         },
         ViewInfo = OperatorInfo { Pos = { 990, -181.5 } },
      },
      TransformC = Transform {
         NameSet = true,
         Inputs = {
            Center = Input { Expression = "Point(0.5, 0+(ScaleC.Output.OriginalHeight/2) / Canvas.Output.OriginalHeight)", },
            ReferenceSize = Input { Value = 1, },
            Input = Input {
               SourceOp = "Merge5",
               Source = "Output",
            },
         },
         ViewInfo = OperatorInfo { Pos = { 990, -115.5 } },
      },
      TransformB = Transform {
         NameSet = true,
         Inputs = {
            Center = Input { Expression = "Point(0.5, 0+(ScaleC.Output.OriginalHeight + Canvas.Padding + ScaleB.Output.OriginalHeight/2) / Canvas.Output.OriginalHeight)", },
            ReferenceSize = Input { Value = 1, },
            Input = Input {
               SourceOp = "Merge4",
               Source = "Output",
            },
         },
         ViewInfo = OperatorInfo { Pos = { 990, -148.5 } },
      },
      Merge2 = Merge {
         Inputs = {
            Background = Input {
               SourceOp = "TransformC",
               Source = "Output",
            },
            Foreground = Input {
               SourceOp = "Merge1",
               Source = "Output",
            },
            PerformDepthMerge = Input { Value = 0, },
         },
         ViewInfo = OperatorInfo { Pos = { 1100, -115.5 } },
      },
      Canvas = Background {
         NameSet = true,
         Inputs = {
            Width = Input { Value = 3840, },
            Height = Input { Value = 2160, },
            ["Gamut.SLogVersion"] = Input { Value = FuID { "SLog2" }, },
            TopLeftAlpha = Input { Value = 0, },
            Padding = Input { Value = 100, },
            Margin = Input { Value = 80, },
         },
         ViewInfo = OperatorInfo { Pos = { 880, -49.5 } },
         UserControls = ordered() {
            Padding = {
               LINKS_Name = "Padding",
               LINKID_DataType = "Number",
               INPID_InputControl = "ScrewControl",
               INP_Default = 0,
               INP_Integer = true,
               INP_MinScale = 0,
               INP_MaxScale = 1920,
               ICS_ControlPage = "Image",
            },
            Margin = {
               LINKS_Name = "Margin",
               LINKID_DataType = "Number",
               INPID_InputControl = "ScrewControl",
               INP_Default = 0,
               INP_Integer = true,
               INP_MinScale = 0,
               INP_MaxScale = 1920,
               ICS_ControlPage = "Image",
            }
         }
      },
      Merge1 = Merge {
         Inputs = {
            Background = Input {
               SourceOp = "TransformB",
               Source = "Output",
            },
            Foreground = Input {
               SourceOp = "TransformA",
               Source = "Output",
            },
            PerformDepthMerge = Input { Value = 0, },
         },
         ViewInfo = OperatorInfo { Pos = { 1100, -148.5 } },
      },
      Crop2 = Crop {
         Inputs = {
            YOffset = Input {
               Value = -80,
               Expression = "-Canvas.Margin",
            },
            XSize = Input { Value = 3840, },
            YSize = Input {
               Value = 2040,
               Expression = "Canvas.Margin+ScaleC.Output.OriginalHeight+Canvas.Padding+ScaleB.Output.OriginalHeight+Canvas.Padding+ScaleA.Output.OriginalHeight+Canvas.Margin",
            },
            Input = Input {
               SourceOp = "Merge2",
               Source = "Output",
            },
         },
         ViewInfo = OperatorInfo { Pos = { 1210, -115.5 } },
      }
   }
}


Now, what might be interesting is to find a way to do this dynamically, so it responds to any number of input images. It could possibly be done with a macro, but you'd have to arbitrarily select the maximum number of images and then find a way to filter for unconnected inputs.
Bryan Ray
http://www.bryanray.name
http://www.sidefx.com
Offline

DavySilva

  • Posts: 183
  • Joined: Thu Mar 03, 2022 12:36 pm
  • Location: UK and Ireland, sometimes EU.
  • Real Name: Davy Silva

Re: Auto Position using Expression

PostFri Jun 17, 2022 6:21 am

Bryan,

This brew my mind. The possibilities are limitless and I love it. I'll keep practising but not sure if I will ever be as good as you.

Thank you for the explanation, it made a lot of sense.
Online Editor and Colourist.
“Never stop learning because life never stops teaching”
Offline

Okke Verbart

  • Posts: 290
  • Joined: Tue Jan 17, 2017 8:40 pm

Re: Auto Position using Expression

PostFri Jun 17, 2022 7:00 am

Sander de Regt wrote:The easiest way to autocrop is by putting

AutoCrop=1

in the frame render script of the crop tool and it does just that.

The downside is of course that it runs every frame, but then again, the same thing goes for expressions as well, so computationallywise it shouldn't make too much difference.


Ah, every day is a learning day! Thanks Sander. Sometimes I do tend to overcomplicate things!
www.ablackbirdcalledsue.com
Offline
User avatar

Bryan Ray

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

Re: Auto Position using Expression

PostMon Jun 20, 2022 2:02 am

Glad to be of service! Let the math flow through you! :lol:
Bryan Ray
http://www.bryanray.name
http://www.sidefx.com

Return to Fusion

Who is online

Users browsing this forum: No registered users and 31 guests