Highlighted

Dynamic keyframe value using expression?

New Here ,
Oct 09, 2018

Copy link to clipboard

Copied

Hi, I'll try my best to explain myself here.

I currently have an animation of a Shape Layer using two keyframes controlling the width of the the shape from 0 px to 100 px.

Now what I want to do is to have the second keyframe value be controlled by an expression (so I can link it & make it "dynamic") WHILE retaining the animation curves (velocity) from my predefined keyframes. Is this at all possible? In my mind it seems pretty basic as I just want to change the value of a specific keyframe while retaining the timing and speed of the predefined keyframes.

All I've seen are solutions where they replace the whole animation with some default ease or linear curve. It's crucial for me here to retain the predefined animation.

I'm thinking a solution would be as simple as this in the expression window:

key(2).value = [x, y]; //where I then would be able to set x to sourceRectAtTime().width of a specific object

Thanks in advance!

TOPICS
Expressions

Views

4.2K

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more

Dynamic keyframe value using expression?

New Here ,
Oct 09, 2018

Copy link to clipboard

Copied

Hi, I'll try my best to explain myself here.

I currently have an animation of a Shape Layer using two keyframes controlling the width of the the shape from 0 px to 100 px.

Now what I want to do is to have the second keyframe value be controlled by an expression (so I can link it & make it "dynamic") WHILE retaining the animation curves (velocity) from my predefined keyframes. Is this at all possible? In my mind it seems pretty basic as I just want to change the value of a specific keyframe while retaining the timing and speed of the predefined keyframes.

All I've seen are solutions where they replace the whole animation with some default ease or linear curve. It's crucial for me here to retain the predefined animation.

I'm thinking a solution would be as simple as this in the expression window:

key(2).value = [x, y]; //where I then would be able to set x to sourceRectAtTime().width of a specific object

Thanks in advance!

TOPICS
Expressions

Views

4.2K

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Oct 09, 2018 0
Most Valuable Participant ,
Oct 10, 2018

Copy link to clipboard

Copied

I'm thinking a solution would be as simple as this in the expression window:

No, it isn't. Keyframe values are read-only to begin with. Any expression can only overwrite/ modify the actual values, not persistently set them in any form. It's inherent in how AE evaluates property streams:

Property base value --> Keyframe value --> Expression result

Furthermore, retaining custom interpolation curves can only be done by referencing an existing curve using valueAtTime() and manipulating the actual time that is used for sampling the value. So if you wanted to reference your existing interpolation, it would still be something like

thisLayer.transform.position.valueAtTime(myTime)[0];

for the X position for instance. myTime could then be defined as your retimed original animation:

myTime=linear(time, key(1).time,key(2).time,newStartTime,newEndTime);

In any case, you need to adapt your thinking. It's more complex than just a single line bit of code.

Mylenium

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Reply
Loading...
Oct 10, 2018 0
Explorer ,
Oct 21, 2019

Copy link to clipboard

Copied

My apologies for posting on a thread that's been inactive for a year, but I was facing this exact same problem in the middle of a big project with a short timeline. Now that the project is over and I've had some time to think about it without a deadline hanging over my head, I think I've solved the problem and wanted to add my solution here in case it helps anyone in the future.

 

 

//reference to the property you've animated
prop = thisProperty
//reference to the first keyframe of the property you've animated
firstKey = prop.key(1).time;
//reference to the last keyframe of the property you've animated
lastKey = prop.key(prop.numKeys).time;
//the total distance traveled between your two keyframes
distanceTotal = prop.valueAtTime(lastKey) - prop.valueAtTime(firstKey);
//the distanced that's already been traveled on any given frame
distanceCurrent = prop.valueAtTime(lastKey) - prop.valueAtTime(time);
//the percentage of the total animation that's been completed on a given frame
percentage = 1 - distanceCurrent/distanceTotal;
//reference to a slider on a control layer that is used to modify the value of our
//final keyframe
offset = thisComp.layer("controls").effect("property offset")("Slider");
//sets the value of the property to be it's current value plus a percentage of the value
//we set with our slider
value + offset*percentage;

 

 

In my example, I was modifying the X Position after having separated dimensions, but this could easily be adapted to any property by just changing what property is being referenced by pos. It works with both positive and negative numbers entered on the slider, allowing you to either increase or decrease the animation, and it handles animations with more than just two keyframes, distributing the offset correctly across the whole animation.

 

The only limitation is that the slider is used to offset the position of your final keyframe, not to set an absolute value for it, but I would think that for the purposes of adjusting templates, that's how you would want it to work anyway.

 

Hopefully this will be useful to someone!

 

*EDIT* I adjusted my expression to just reference the property it's on, so now you can just paste it onto any property you want to adjust and all you'd have to change is relinking offset to your slider control.

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Reply
Loading...
Oct 21, 2019 0
Adobe Community Professional ,
Oct 21, 2019

Copy link to clipboard

Copied

That might work but I think you have created a recursive expression. I am pretty sure that the greater the distance between keyframes the longer it is going to take to make the calculations. I have not checked but I suspect that if the time between keyframes is 10 frames and it takes 10 seconds to render, when you change the time between keyframes to 60 frames, the time to render may increase to something like 100 seconds, but if you change the time between keyframes to 120 frames the time to render may increase to 500 seconds.  Make sure you check that out before you start sending things to the render cue. Any time you add .time to your expression and ask it to look forward or backward you are asking for an exponential increase in the time it takes to make the calculations.  If the times get rediculous the best thing you can do is to try using the Keyframe Assistant to convert the expression to keyframes. 

 

You might want to check out this thread by Dan Ebberts. Check the last entry.

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Reply
Loading...
Oct 21, 2019 0
Explorer ,
Oct 21, 2019

Copy link to clipboard

Copied

You are correct, I went ahead and checked this in my test comp and here's what I discovered: In a 4 minute long composition there was a 1 minute difference in render time between a version with keyframes 1 second apart and a version with keyframes 4 minutes apart. There was a 1 second render time difference between versions with keyframes 1 second apart and keyframes 10 seconds apart. So your mileage may vary depending on what you are trying to do.

 

For my purposes, I was working on making dynamically resizeable templates for lower third graphics that only had animation lengths of a few seconds and I barely noticed the impact to render time. If you tried to apply this to a 10 minute long animation you'd definitely notice the increase and in that situation someone far smarter than me could probably come up with a more elegant solution.

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Reply
Loading...
Oct 21, 2019 0
Community Beginner ,
Oct 26, 2020

Copy link to clipboard

Copied

Also appologies for chiming in yet another year later, but... This worked really well for me! Thanks for sharing. I ended up setting my first keyframe value (the width of a rectangle shape) to 0 and the second keyframe to 1 (because the math errors out when you set it to 0 as well). Then I set up an expression on the offset slider control setting the offset equal to the sourceRectAtTime().width value of my text layer + a slider control for padding. Which looked something like this:

var s = thisComp.layer("Name  Placeholder Company  Placeholder");
var w = s.sourceRectAtTime().width;
var p = effect("Padding")("Slider");

w+p

The width of the box will technically be off by 1 pixel, but you'll never hear me complain about it!

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Reply
Loading...
Oct 26, 2020 0