Christian Geijer
Forum Replies Created
-
Christian Geijer
December 16, 2019 at 8:37 am in reply to: Editing graph when an ‘ease’ expression is usedHey, I’m not sure if this is what you want, but I’ve put together a script to be able to do an in animation from value1 to value2, hold value2 and then do an out animation from value2 to value3 with custom easing curves and timings.
To set it up, create a null and name it “Control”. Create two sliders, one named “Anim in” and one named “Anim out”. Add keyframes to “Anim in” that goes from 0 to 100. Add keyframes to “Anim out” that goes from 100 to 0. Apply the animation curves that you want the animations to have.
In the script, change the timing values under // TIMINGS and change the actual values that you want to animate from and to under // VALUES.
It’s not perfect and there’s probably loads of better ways to do it, but it has worked for me.
// KEYS
iAnimInKeys = thisComp.layer("Control").effect("Anim in")("Slider");
iAnimOutKeys = thisComp.layer("Control").effect("Anim out")("Slider");// SLIDERS MIN/MAX
n = iAnimInKeys.numKeys;
inMinVal = Infinity;
inMaxVal = -Infinity;for (var i = 1; i <= n; i++) {
if(iAnimInKeys.key(i).value < inMinVal) {
inMinVal = iAnimInKeys.key(i)
}
if(iAnimInKeys.key(i).value > inMaxVal) {
inMaxVal = iAnimInKeys.key(i)
}
}n = iAnimOutKeys.numKeys;
outMinVal = Infinity;
outMaxVal = -Infinity;for (var i = 1; i <= n; i++) {
if(iAnimOutKeys.key(i).value < outMinVal) {
outMinVal = iAnimOutKeys.key(i)
}
if(iAnimOutKeys.key(i).value > outMaxVal) {
outMaxVal = iAnimOutKeys.key(i)
}
}
iAnimInMin = inMinVal;
iAnimInMax = inMaxVal;iAnimOutMax = outMaxVal;
iAnimOutMin = outMinVal;// TIMINGS
tAnimInStart = 0;
tAnimInDuration = 0.5;tAnimOutDuration = 0.5;
tAnimOutStart = 3;// VALUES
inVal = 0;
holdVal = 100;
outVal = 0;// ANIM VALUES CALC
iAnimInVal1 = inVal - ((holdVal - inVal) * (iAnimInMin/-100));
iAnimInVal2 = inVal + ((holdVal - inVal) * (iAnimInMax/100));iAnimOutVal1 = outVal - ((holdVal - outVal) * (iAnimOutMin/-100));
iAnimOutVal2 = outVal + ((holdVal - outVal) * (iAnimOutMax/100));// ANIMATION
if (time < tAnimInStart){
animVal = inVal} else if (time >= tAnimInStart && time < (tAnimInStart + tAnimInDuration)) {
t = time - tAnimInStart;
d = iAnimInKeys.key(iAnimInKeys.numKeys).time - iAnimInKeys.key(1).time;
animVal = linear(iAnimInKeys.valueAtTime(iAnimInKeys.key(1).time + d*t/tAnimInDuration), iAnimInMin, iAnimInMax, iAnimInVal1, iAnimInVal2)} else if(time >= (tAnimInStart + tAnimInDuration) && time < tAnimOutStart) {
animVal = holdVal} else if (time >= tAnimOutStart && time < (tAnimOutStart + tAnimOutDuration)) {
t = time - tAnimOutStart;
d = iAnimOutKeys.key(iAnimOutKeys.numKeys).time - iAnimOutKeys.key(1).time;
animVal = linear(iAnimOutKeys.valueAtTime(iAnimOutKeys.key(1).time + d*t/tAnimOutDuration), iAnimOutMin, iAnimOutMax, iAnimOutVal1, iAnimOutVal2);} else {
animVal = outVal}
animVal
-
Christian Geijer
May 8, 2019 at 9:38 am in reply to: Use A Null Slider To Interpolate Between Series Of PositionsThis maybe isn’t exactly what you want but it might help you on your way.
One way could be to create a .json-file with all the different positions mapped to the corresponding slider value like this:
{
"positions": {
"1": {
"x": 2,
"y": 54
},
"2": {
"x": -4,
"y": -174
}
}
}Place the .json-file (here named data.json) in your composition and then, with the value from Master slider (in my example placed on a null layer named “Control”), change the position of the object you want to move around with an expression that looks something like this:
id = thisComp.layer("Control").effect("Master slider")("Slider").toString;
x = thisComp.layer("data.json").source.sourceData.positions[id].x;
y = thisComp.layer("data.json").source.sourceData.positions[id].y;
[x,y]
This, however, only works with the slider being set to whole numbers that you also have defined in data.json and does not work if the slider animates between the different values. You maybe can define the first and second positions and use linear() to animate between them, but I’m not sure how you’d want that to work in your specific case.
-
This is one way. Apply this to the scale property.
L = thisLayer;
w = L.sourceRectAtTime().width;maxW = 500;
sca = (maxW/w) * 100;[sca, sca]
-
I just wanted to return to this in case any stray googler finds this and wonders the same thing.
I think I’ve solved it. I’m going to expand on this and build some more control over the timings, but the foundation that I’ve built is this. If anyone have some tips for improvement, I appreciate any pointers. But as for now, I think it works.Cheers!
iAnimInKeys = thisComp.layer("Control").effect("Anim in")("Slider");
iAnimOutKeys = thisComp.layer("Control").effect("Anim out")("Slider");tAnimInStart = 1;
tAnimInDuration = 0.5;tAnimOutDuration = 0.5;
tAnimOutStart = 3;holdVal = 880;
inVal = 200;
outVal = 540;if (time < tAnimInStart){
inVal} else if (time >= tAnimInStart && time < (tAnimInStart + tAnimInDuration)) {
t = time - tAnimInStart;
d = iAnimInKeys.key(2).time - iAnimInKeys.key(1).time;
linear(iAnimInKeys.valueAtTime(iAnimInKeys.key(1).time + d*t/tAnimInDuration), 0, 100, inVal, holdVal)} else if(time >= (tAnimInStart + tAnimInDuration) && time < tAnimOutStart) {
holdVal} else if (time >= tAnimOutStart && time < (tAnimOutStart + tAnimOutDuration)) {
t = time - tAnimOutStart;
d = iAnimOutKeys.key(2).time - iAnimOutKeys.key(1).time;
linear(iAnimOutKeys.valueAtTime(iAnimOutKeys.key(1).time + d*t/tAnimOutDuration), 0, 100, outVal, holdVal);} else {
outVal}
-
Awesome. Thanks for the tip!
-
Hi,
A large and late bump, but I thought to reply here instead of starting a new thread.
I have a template where I’ve placed two sliders with two keyframes each on a control null.
These two sliders are the “masters” for different animations within the comp. One for “build in” and one for “build out”:I’ve written an expression that I can apply to every layer and property I want to control with a linear-function mapped to the “masters”.
It looks like this:
animIn = thisComp.layer("Control").effect("Anim in")("Slider");
animOut = thisComp.layer("Control").effect("Anim out")("Slider");
dur = thisComp.layer("Control").effect("Duration")("Slider");inBuffer = 0;
outBuffer = 0;animInTime = animIn.key(2).time - animIn.key(1).time;
animOutTime = animOut.key(2).time - animOut.key(1).time;animInStart = 0 + inBuffer;
animOutStart = dur - animOutTime - outBuffer;// calculations for inVal, holdVal, outVal, if needed
holdVal = 100;
inVal = 0;
outVal = inVal;if(time <= animInStart) {
inVal
} else if(time >= animInStart && time < animInStart + animInTime) {
linear(animIn.valueAtTime(time - animInStart), 0, 100, inVal, holdVal)
} else if(time >= animOutStart) {
linear(animOut.valueAtTime(time - animOutStart), 0, 100, outVal, holdVal)
} else {
holdVal
}animIn and animOut are the master sliders that go from 0-100 and 100-0 respectively.
The expression uses the animIn-slider to shift from inVal to holdVal and then holds holdVal.
It holds holdVal until it’s time to shift, with the animOut-slider, from holdVal to outVal.I’ve also built in inBuffer and outBuffer so I can stagger the animation if I want to.
I’ve tried to integrate your expression in this thread with mine, but I really can’t get it to work. Both due to that I’m not an expert on expressions and that I really don’t understand how yours works.
In short; I would like to be able to change the duration between the keyframes within animIn and animOut individually with sliders. Is it possible to marry these two expressions together? If yes, how would I go about doing that? Any tips or help you can give me would be appreciated.
Best regards,
/C -
Christian Geijer
August 13, 2018 at 6:50 am in reply to: Combine expressions for position and anchor point with text animatorOf course! Thank you so much for your help.
Have a great week!/C
-
Christian Geijer
June 11, 2018 at 7:55 am in reply to: Is a layer’s startTime set in stone upon creation?Great stuff! Thank you for your help!
/C
-
Hi again.
I appreciate the help, but is it okay if I ask another question regarding this?
Your solution works, but it takes about ten times more time to preview and render. Is that something that is solvable, or are these kinds of looping expressions just too heavy for After Effects? is it possible to reduce the times in any way?Thanks
/C -
Amazing! It works perfectly!
The only thing is that we import the sourceText value from a .json file embedded in the project. When changing the text in that file I get an error.
“Error at line 7 in property ‘Amount’ (…) property or method named 62 in Class ‘TextProperty’ is missing or does not exist.”
But when I enter edit mode in the expression on ‘Amount’ and just apply the expression again, everything works. It somehow doesn’t like having the text changed externally.However, if I import the text value on a different text layer, and point to that sourceText from my first layer, everything works even when updating the values.
If the external connection doesn’t like the .json connection, this is a way to go around it.
Thank you once again. I really appreciate the help.
/C
