Page 1 of 1

Expression syntax to get the Slope of a Spline

PostPosted: Mon Jan 31, 2022 9:13 pm
by brunocbreis
I only just noticed that when you hover a certain point on a spline, Fusion tells me the slope in the bottom left corner, just like it does a Parameter's name when I hover it.

Screen Shot 2022-01-31 at 18.06.14.png
The Slope
Screen Shot 2022-01-31 at 18.06.14.png (7.94 KiB) Viewed 563 times


Is it possible to get that value on a frame basis to use in an expression?

The only way I knew how was to use
Code: Select all
Node:GetValue("Parameter",time) - Node:GetValue("Parameter",time - 1)
or something along those lines, but the problem is I have to retype it every time I want to grab some parameter's velocity in a new comp, which involves setting up custom user controls every time so it's easier to manage, and so on. Since it's something that refers to a different parameter every single time, I don't know that I could package it into a simple macro this easily – and I'm still not capable of creating, say, custom modifiers at this time.

So can we get the slope of a curve with an expression or not? Since Fusion already calculates it, it should be such an easy implementation :cry: Hope version 18 randomly blesses us with such ease

Re: Expression syntax to get the Slope of a Spline

PostPosted: Tue Feb 01, 2022 6:57 am
by Sander de Regt
Before trying to answer, can you explain what you want to use it for? I have an idea, but maybe that won't work for you.

Re: Expression syntax to get the Slope of a Spline

PostPosted: Tue Feb 01, 2022 12:48 pm
by brunocbreis
The example I could think of was to use it for some sort of semi-automated "squash and stretch" (I use Fusion mainly for motion graphics... I know, I hate aft*er ef**cts).

Here's an implemented example.

Code: Select all
{
   Tools = ordered() {
      glowy_ball = GroupOperator {
         CtrlWZoom = false,
         NameSet = true,
         Outputs = {
            Output1 = InstanceOutput {
               SourceOp = "Glow1",
               Source = "Output",
            }
         },
         ViewInfo = GroupInfo {
            Pos = { 605, 16.5 },
            Flags = {
               AllowPan = false,
               GridSnap = true,
               AutoSnap = true,
               RemoveRouters = true
            },
            Size = { 236, 97.8864, 118, 24.2424 },
            Direction = "Horizontal",
            PipeStyle = "Direct",
            Scale = 1,
            Offset = { -550, 23.6591 }
         },
         Tools = ordered() {
            Glow1 = Glow {
               Inputs = {
                  Blend = Input { Value = 0.2, },
                  Filter = Input { Value = FuID { "Fast Gaussian" }, },
                  XGlowSize = Input { Value = 17, },
                  Glow = Input { Value = 0.825, },
                  ApplyMode = Input { Value = 1, },
                  Input = Input {
                     SourceOp = "Background1",
                     Source = "Output",
                  },
               },
               ViewInfo = OperatorInfo { Pos = { 605, 16.5 } },
            },
            Background1 = Background {
               Inputs = {
                  GlobalOut = Input { Value = 24, },
                  Width = Input { Value = 1920, },
                  Height = Input { Value = 1080, },
                  ["Gamut.SLogVersion"] = Input { Value = FuID { "SLog2" }, },
                  TopLeftRed = Input { Value = 0.961, },
                  TopLeftGreen = Input { Value = 0.191239, },
                  TopLeftBlue = Input { Value = 0.671569863999999, },
                  EffectMask = Input {
                     SourceOp = "Ellipse1",
                     Source = "Mask",
                  }
               },
               ViewInfo = OperatorInfo { Pos = { 495, 16.5 } },
            },
            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.0510735444672136, },
                  Height = Input { Value = 0.0510735444672136, },
               },
               ViewInfo = OperatorInfo { Pos = { 495, -16.5 } },
            }
         },
      },
      XFSquash = Transform {
         NameSet = true,
         Inputs = {
            Center = Input {
               SourceOp = "Path1",
               Source = "Position",
            },
            UseSizeAndAspect = Input { Value = 0, },
            XSize = Input { Expression = "Velocity < Threshold and 1 or (1 + Velocity * Amount)", },
            YSize = Input { Expression = "1/XSize", },
            Angle = Input {
               SourceOp = "Path1",
               Source = "Heading",
            },
            Input = Input {
               SourceOp = "Glow1",
               Source = "Output",
            },
            Amount = Input { Value = 0.76, },
            Velocity = Input { Expression = "0 and (Path1:GetValue(\"Displacement\",time+.5)-Path1:GetValue(\"Displacement\",time-.5))", },
            Threshold = Input { Value = 0.114, },
         },
         ViewInfo = OperatorInfo { Pos = { 715, 16.5 } },
         UserControls = ordered() {
            Amount = {
               LINKS_Name = "Amount",
               LINKID_DataType = "Number",
               INPID_InputControl = "SliderControl",
               INP_Default = 0,
               INP_Integer = false,
               ICS_ControlPage = "Controls",
            },
            Velocity = {
               LINKS_Name = "Velocity",
               LINKID_DataType = "Number",
               INPID_InputControl = "ScrewControl",
               INP_Integer = false,
               ICS_ControlPage = "Controls",
            },
            Threshold = {
               LINKS_Name = "Threshold",
               LINKID_DataType = "Number",
               INPID_InputControl = "SliderControl",
               INP_Default = 0,
               INP_Integer = false,
               ICS_ControlPage = "Controls",
            }
         }
      },
      Path1 = PolyPath {
         DrawMode = "InsertAndModify",
         CtrlWZoom = false,
         Inputs = {
            Displacement = Input {
               SourceOp = "Path1Displacement",
               Source = "Value",
            },
            PolyLine = Input {
               Value = Polyline {
                  Points = {
                     { Linear = true, LockY = true, X = -0.272210884353742, Y = -0.205562273276904, RX = 0.146595096371882, RY = 0.388956066102378 },
                     { LockY = true, X = 0.349207057823129, Y = 0.126964933494559, LX = -0.180608701814059, LY = -0.26440951229343 }
                  }
               },
            },
         },
      },
      Path1Displacement = BezierSpline {
         SplineColor = { Red = 255, Green = 0, Blue = 255 },
         NameSet = true,
         KeyFrames = {
            [4] = { 0, RH = { 8, 0 }, Flags = { Linear = true, LockedY = true } },
            [16] = { 1, LH = { 7.63636363636364, 1 }, Flags = { LockedY = true } }
         }
      },
      Merge1 = Merge {
         Inputs = {
            Background = Input {
               SourceOp = "Background2",
               Source = "Output",
            },
            Foreground = Input {
               SourceOp = "XFSquash",
               Source = "Output",
            },
            PerformDepthMerge = Input { Value = 0, },
         },
         ViewInfo = OperatorInfo { Pos = { 715, 49.5 } },
      },
      Background2 = Background {
         Inputs = {
            GlobalOut = Input { Value = 24, },
            Width = Input { Value = 1920, },
            Height = Input { Value = 1080, },
            ["Gamut.SLogVersion"] = Input { Value = FuID { "SLog2" }, },
            TopLeftGreen = Input { Value = 0.063, },
            TopLeftBlue = Input { Value = 0.126, },
         },
         ViewInfo = OperatorInfo { Pos = { 605, 49.5 } },
      }
   }
}


I do think this could be useful for other applications, though, where I would not necessarily use a Transform node and refer to a Path within it.