Copy link to clipboard
Copied
I'm trying to dynamically adjust keyframe values, & I'm pretty much successfull. but problem is after effects only catch one linear expression (first & second keyframe can be dynamically change) but not others. how to do that? please help.
oh, yes, I forgot that Ae's linear behaves strange when linear(t,t1,t2,...) t1 > t2.
Therefore, my expression only works if the value is increasing, not when it is going down.
Does this one work as expected for you?
keyValues = [60,40,100,60];
function myLinear(t,tMin,tMax,vMin,vMax) {
if(tMax< tMin){
var temp = tMax;
tMax=tMin;
tMin=temp;
temp=vMax;
vMax=vMin;
vMin=temp;
}
var result = vMin;
if(tMin==tMax){
result = vMin;
}
else {
result= vMin+( (t-tMin)/(tMax-tMin))*(vMax-vMin);
}
return result;
}
val = val
Copy link to clipboard
Copied
You cannot simply daisy-chain these functions. If you want multiple interpolations you have to run them in a loop or determine in which "segemnt" between keys you are by using the nearestKey() method and then figure out the indices of the preceding and subsequent key. Point in case: You only have one linear functions and substitute its internal values with variables. Dan's old expression reference has enough examples of this e.g. here:
http://www.motionscript.com/articles/bounce-and-overshoot.html
Mylenium
Copy link to clipboard
Copied
Please can you you show me example how to do that? please sir! :fallen_leaf:😊
Copy link to clipboard
Copied
Copy link to clipboard
Copied
Have a look at the keyframe overshoot example I already linked. It's basically all there already:
if (numKeys > 0){
n = nearestKey(time).index;
if (key(n).time > time);
All that would be required is to rewrite the code to give you the index and time of the two keyframes defining a segement and then feed those parameters into a single linear() function.
Mylenium
Copy link to clipboard
Copied
Yeah I got it. Thank you Sir as always your support straight to the point. 👌 😍
Copy link to clipboard
Copied
@Mylenium Sorry sir, for disturbing you but still need help? Can you code this for me?
Only two keframes's values can be dynamically changed, you can see third is flat.... Please give me exact code...
I'm noob n I've to still learning a lot. As a expert, I think only you can solve this... 8):gear:
Copy link to clipboard
Copied
You probably want this?
var keyValues = [20,60,100,60];
var i = 1;
while((i<=numKeys) && (key(i).value < time)) i++;
result = keyValues[0];
if(numKeys > 0 && i>numKeys) result = keyValues[numKeys-1];
else if(i>1) result = linear(time, key(i-1),key(i),keyValues[i-2],keyValues[i-1])
result
Copy link to clipboard
Copied
It only catches first keyframe as you can see in the screenshot... which is first value 50
Copy link to clipboard
Copied
What are your keyframe values? The expression expects times in seconds.
So if the first keyframe has a value of 3 and then second one of 5, it will animate from 50% to 60% starting at time 3s and ending at 5s.
Copy link to clipboard
Copied
I guess your keyframe values are so big, that the animation only starts after the end of the comp.
Copy link to clipboard
Copied
Sir I just want to set all keyframe values dynamically.
Suppose, I keframed values like this: first keyframe- 20, second- 40, third- 60, fourth- 50 okay.
but now i want to change them dynamically using expression: first keyframe- 40, second keyframe- 70, third keyframe- 20, fourth keyframe- 10. I think now you got it what i'm looking for. I tried a lot myself but failed evertime... I'm attaching after effect project file.
please see if you can do this, it's a huge gift for me! 🙂
Copy link to clipboard
Copied
If you don't get that file please go here: https://we.tl/t-FrMeTDqUIl Thank You!
Copy link to clipboard
Copied
@Mathias Moehl Sorry sir but can you solve my problem?
Copy link to clipboard
Copied
I think you might be looking for something like this:
keyValues = [60,40,100,60];
val = value;
if (numKeys > 0){
n = nearestKey(time).index;
if (time < key(n).time) n--;
if (n < 1){
val = keyValues[0];
}else if (n == numKeys){
val = keyValues[keyValues.length-1];
}else{
v1 = keyValues[n-1];
v2 = keyValues[n];
val = ease(time,key(n).time,key(n+1).time,v1,v2);
}
}
val
Copy link to clipboard
Copied
Oh, I thought you want to store the time of the keys in the actual keyframe values.
Dan's code is great, if you want to keep the time of the keys and just replace the values.
If you have a 1D property like Opacity, you should also be able to replace the line
val = ease(time,key(n).time,key(n+1).time,v1,v2);
by
val = linear(value,key(n).value,key(n+1).value,v1,v2);
to preserve the original easing (instead of always using Easy Ease)
Copy link to clipboard
Copied
@Dan Ebberts Thank You for helping me sir. As @Mathias Moehl Sir told easing is not catching otherwise all values can be dynamically changed!!! (Note: I have set all values to it's original keyframed values so you can see custom easing is not cathing).
@Mathias Moehl After adding your code line here's what i get 😂 two keyframes are catching custom easing but other are going weird
Here's with @Dan Ebberts script: Download Sample File (Example File).
Here's with @Dan Ebberts script: Download Sample File (Example File).
Somrthing is still missing...
Copy link to clipboard
Copied
Second example file is dan + mathias sir script... I forgot to mention there...
Copy link to clipboard
Copied
hello Sir, @Mathias Moehl @Dan Ebberts forgot me? can you help... please...
Copy link to clipboard
Copied
The basic problem is that expressions cannot modify keyframes--they can only change the current value of the property. Also, expressions don't have access to keyframe easing information. I can't think of a general solution that solves your problem, where you want to keep your custom easing, but change the value.
Copy link to clipboard
Copied
The basic problem is that expressions cannot modify keyframes By @Dan Ebberts
This expression is called "Expo" and can alter easing....
/* ---------- Flow Function Declarations ---------- */
function expo(t,tMin,tMax,value1,value2){if(arguments.length!==5)return value;var a=value2-value1;var b=tMax-tMin;var c=clamp((t-tMin)/(b/2),0,2);if(c<1)return a/2*Math.pow(2,10*(c-1))+value1;c--;return a/2*(-Math.pow(2,-10*c)+2)+value1;};
/* ---------- Flow Function Declarations ---------- */
/* ---------- Flow Expression Template ------------ */
var animationStartTime = 1;
var animationEndTime = 2;
var startValue = value;
var endValue = value * 2;
if (numKeys > 0) {
var nearestKeyIndex = nearestKey(time).index;
if (key(nearestKeyIndex).time > time) nearestKeyIndex--;
if (nearestKeyIndex === 0 || nearestKeyIndex === numKeys) {
startValue = endValue = value;
} else {
animationStartTime = key(nearestKeyIndex).time;
animationEndTime = key(nearestKeyIndex + 1).time;
startValue = key(nearestKeyIndex).value;
endValue = key(nearestKeyIndex + 1).value;
}
}
expo(time, animationStartTime, animationEndTime, startValue, endValue);
/* ---------- Flow Expression Template ------------ */
Copy link to clipboard
Copied
Sure, you can craft an expression that will generate any kind of easing you want (like your or example, or the one I provided) which will completely ignore the existing ease generated by the keyframes, but I thought you wanted to preserve the keyframed ease. I guess it's not clear to me exactly what you're after...
Copy link to clipboard
Copied
I want to change vaules of all keyframes with my custom easing... Simple...
example here: quad ease expression. joint it with linear to preseve easing. but instead "Linear" i used "quad" & it works!
/* ---------- Flow Function Declarations ---------- */
function quad(t,tMin,tMax,value1,value2){if(arguments.length!==5)return value;var a=value2-value1;var b=tMax-tMin;var c=clamp((t-tMin)/(b/2),0,2);if(c<1)return a/2*Math.pow(c,2)+value1;c--;return -a/2*(c*(c-2)-1)+value1;};
/* ---------- Flow Function Declarations ---------- */
/* ---------- Flow Expression Template ------------ */
var animationStartTime = 1;
var animationEndTime = 2;
var startValue = value;
var endValue = value * 2;
if (numKeys > 0) {
var nearestKeyIndex = nearestKey(time).index;
if (key(nearestKeyIndex).time > time) nearestKeyIndex--;
if (nearestKeyIndex === 0 || nearestKeyIndex === numKeys) {
startValue = endValue = value;
} else {
animationStartTime = key(nearestKeyIndex).time;
animationEndTime = key(nearestKeyIndex + 1).time;
startValue = key(nearestKeyIndex).value;
endValue = key(nearestKeyIndex + 1).value;
}
}
quad(time, animationStartTime, animationEndTime, startValue, endValue);
/* ---------- Flow Expression Template ------------ */
sliderControl = comp("Title 02").layer("Setting").effect("MF - Lines")(1);
if (numKeys > 1){
t1 = key(1).time;
t2 = key(2).time;
t3 = key(3).time;
t4 = key(4).time;
v1 = [25];
v2 = [40];
v3 = [50];
v4 = [70];
if (time < key(2).time)
quad(time, t1, t2, v1, v2); else quad(time, t2, t3, v2, v3);
if (time < key(3).time)
quad(time, t1, t2, v1, v2); else quad(time, t3, t4, v3, v4);
} else {
value
}
Copy link to clipboard
Copied
So really, all you're preserving from the original keyframes is the timing, yes?
Copy link to clipboard
Copied
yes