Keyframes Question: Delay adjustment by a set number of frames?

Participant ,
Sep 12, 2022 Sep 12, 2022

Copy link to clipboard

Copied

Hi all, got a question--is there a way to do something like this?

 

Time: 0:00:00

Keyframe 1: 0:00:00

Position X: 100

Actual Position: 100



Time: 0:04:00

Keyframe 2: 0:04:00

Position X: 250

Actual Position: 100



Time: 0:05:00

Actual position: 250

 

Basically, I'm looking to be able to set a keyframe (assume that they're all more than 1-2 seconds apart), and when AfterEffects detects the next keyframe (I'm imagining all of them being set to Hold interpolation), it'll backtrack from the keyframe's time by a set number of frames--I'm thinking 30 to start with--to start actually adjusting the property, so that by the time of Keyframe #2, the everything is where the keyframe says it should be. (Preferably with an Ease interpolation.) Alternatively, I could also do it the other way, I set a keyframe and then it takes 1-2 seconds for the object to actually shift to match the new value.

 

(And yes, I know this is a lot easier to do with multiple keyframes, but there's a reason I'm specifically looking to do this in this manner.)

 

I'm no stranger to sliders so if it would take a property being parented to a slider so it can compare last keyframe to next keyframe, I can do that too.

TOPICS
Expressions , How to

Views

141

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
community guidelines

correct answers 1 Correct answer

Community Expert , Sep 16, 2022 Sep 16, 2022

Try this one:

easeFrames = 30;
val = value;
if (numKeys > 0){
  n = nearestKey(time).index;
  if (time < key(n).time) n--;
  if (n > 1){
    d = framesToTime(easeFrames);
    t1 = key(n).time;
    if (n < numKeys){
      d = Math.min(d,key(n+1).time - t1);
    }
    t2 = t1 + d;
    v1 = key(n-1).value;
    v2 = key(n).value;
    val = ease(time,t1,t2,v1,v2);
  }
}
val

Likes

Translate

Translate
Community Expert ,
Sep 12, 2022 Sep 12, 2022

Copy link to clipboard

Copied

That's no different than the usual fake bounce/ inertia/ overshoot expressions as found here:

 

http://www.motionscript.com/articles/bounce-and-overshoot.html

 

You just have to play with the parameters. Of course it won't work too well with hold keyframes and you may have to change your approach on that. Otherwise of course all manner of expressions can be created with valueAtTime() to mimic such behaviors and/ or the ones provided by Dan Ebberts be modified to suit.

 

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
community guidelines
Participant ,
Sep 12, 2022 Sep 12, 2022

Copy link to clipboard

Copied

Mylenium, actually what I described is completely different than bounce/inertia/overshoot expressions. You've managed to miss the point of what I'm trying to do entirely. And if you'll kindly re-read my post in its entrety, you'll notice that I have a problem that's more or less only solvable with Hold keyframes. So, more or less per usual, your reply is of no help whatsoever.

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
community guidelines
Community Expert ,
Sep 12, 2022 Sep 12, 2022

Copy link to clipboard

Copied

I think that would be like this:

easeFrames = 30;
val = value;
if (numKeys > 0){
  n = nearestKey(time).index;
  if (time > key(n).time && n < numKeys) n++;
  if (n > 1){
    d = framesToTime(easeFrames);
    t2 = key(n).time;
    t1 =  Math.max(key(n-1).time, t2 - d)
    v1 = key(n-1).value;
    v2 = key(n).value;
    val = ease(time,t1,t2,v1,v2);
  }
}
val

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
community guidelines
Participant ,
Sep 12, 2022 Sep 12, 2022

Copy link to clipboard

Copied

I will give that a go Dan; many thanks!

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
community guidelines
Participant ,
Sep 16, 2022 Sep 16, 2022

Copy link to clipboard

Copied

I finally had time to try this tonight, it's working exactly as we'd talked about but it doesn't work quite as well as I'd thought. Is there a way to reverse the effect, so that the delayed implemention starts at the keyframe itself instead of ending at 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
community guidelines
Community Expert ,
Sep 16, 2022 Sep 16, 2022

Copy link to clipboard

Copied

Try this one:

easeFrames = 30;
val = value;
if (numKeys > 0){
  n = nearestKey(time).index;
  if (time < key(n).time) n--;
  if (n > 1){
    d = framesToTime(easeFrames);
    t1 = key(n).time;
    if (n < numKeys){
      d = Math.min(d,key(n+1).time - t1);
    }
    t2 = t1 + d;
    v1 = key(n-1).value;
    v2 = key(n).value;
    val = ease(time,t1,t2,v1,v2);
  }
}
val

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
community guidelines
Participant ,
Sep 16, 2022 Sep 16, 2022

Copy link to clipboard

Copied

Dan to the rescue as always. Many thanks sir!

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
community guidelines
Community Expert ,
Sep 17, 2022 Sep 17, 2022

Copy link to clipboard

Copied

Dan that is some amazing code. 

I have been fiddling with it a bit, but I can't figure out why you need a second keyframe to keep it from moving between the first and second keyframe. If I use the expression on rotation and set keyframes 30º apart, the layer rotates the first 30", snaps back to 0º, then starts the easing between values. I get this:

RickGerard_0-1663416067427.gif

If I duplicate the first keyframe, it solves the problem:

RickGerard_1-1663416111965.gif

I can't figure out how to keep the move to happen without the duplicate keyframe.

 

If I use your first expression, the one that completes the move at the next keyframe, I don't need the duplicate keyframe.

 

Thanks.

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
community guidelines
Community Expert ,
Sep 17, 2022 Sep 17, 2022

Copy link to clipboard

Copied

Rick,

I set it up based on the assumption that the keyframes would all be hold keyframes. In the first version, the first movement starts as you come into the 2nd keyframe. In the second version, the movement starts as you come out of the 2nd keyframe. I hope that makes sense. I didn't really think about how it might work (or not work, as you've discovered) with linear keyframes.

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
community guidelines
Participant ,
Sep 17, 2022 Sep 17, 2022

Copy link to clipboard

Copied

So to expand on what problem this is solving for me and why I was specific with Hold keyframes--remember the AE project that we set up to basically act as a TV switcher? This is for that. One of the features I built in was one where I could pan and scan the different inputs, but in the recent episode I did with it, one of my guests was constantly moving around, which was forcing me to make constant adjustments. A test export I did showed that in a couple of places I'd actually messed up and not applied keyframes correctly (short version, I was trying to use a combination of Ease and Hold keyframes, and with my particular workflow that wasn't the best idea).

 

So, what Dan's solution is going to let me do is start with a set of Hold keyframes for all three attributes that I might change for the camera inputs--X offset, Y offset, and Scale Adjust--and then whenever someone moves and I have to pan-and-scan to compensate, all I have to do is make an adjustment to whatever properties are appropriate using a Hold keyframe, and AfterEffects will use those single keyframes (which are pretty much idiot-proof) to implement a shift that's consistent, smooth, and professional-looking.

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
community guidelines
Community Expert ,
Sep 17, 2022 Sep 17, 2022

Copy link to clipboard

Copied

Thanks, Dan. I find the first expression incredibly useful and have saved it with some modifications as an animation preset. You can quickly add keyframes in the timeline, or even markers, then make adjustments to the keyframes while you are watching. It's another brilliant idea from Dan the Man...

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
community guidelines
Community Expert ,
Sep 17, 2022 Sep 17, 2022

Copy link to clipboard

Copied

So I guess to get the second version to work with linear keyframes, you'd just need to hold the value of the first keyframe until you get to the second keyframe:

easeFrames = 30;
val = value;
if (numKeys > 0){
  n = nearestKey(time).index;
  if (time < key(n).time) n--;
  if (n > 1){
    d = framesToTime(easeFrames);
    t1 = key(n).time;
    if (n < numKeys){
      d = Math.min(d,key(n+1).time - t1);
    }
    t2 = t1 + d;
    v1 = key(n-1).value;
    v2 = key(n).value;
    val = ease(time,t1,t2,v1,v2);
  }else{
    val = key(1).value;
  }
}
val

 

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
community guidelines
Community Expert ,
Sep 17, 2022 Sep 17, 2022

Copy link to clipboard

Copied

I think the first version is more useful because you can see what you are doing when you add a keyframe. 

 

I modified the first version to work with Markers and sliders to modify more than one property with a single expression for an animated Timeline project. It's going to save me a bunch of time. Thanks again Dan.

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
community guidelines
Community Expert ,
Sep 17, 2022 Sep 17, 2022

Copy link to clipboard

Copied

Thanks Rick, I'd love to see what you've done with 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
community guidelines
Community Expert ,
Sep 17, 2022 Sep 17, 2022

Copy link to clipboard

Copied

LATEST

I'm out in the field today but when I get back I will post 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
community guidelines
Participant ,
Sep 16, 2022 Sep 16, 2022

Copy link to clipboard

Copied

I've been able to figure it out at least part way:

easeFrames = thisComp.layer("Shape Dynamics").effect("DelayFrames")("Slider");
val = value;
if (numKeys > 0){
  n = nearestKey(time).index;
  if (time > key(n).time && n < numKeys) n++;
  if (n > 1){
    d = framesToTime(easeFrames);
    t2 = key(n).time;
    t1 =  Math.max(key(n).time, t2 + d)
    v1 = key(n-1).value;
    v2 = key(n).value;
    val = ease(time,t1,t2,v1,v2);
  }
}
val

But this only works with two keyframes. Try as I might I can't get this to work with three or more keyframes.

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
community guidelines