ADOBE AFTER EFFECTS: Forum Expressions Tutorials Creative Cloud

OVERSHOOT expression only based on Velocity - NOT keyframes

COW Forums : Adobe After Effects Expressions

<< PREVIOUS   •   FAQ   •   VIEW ALL   •   PRINT   •   NEXT >>
Remi Monedi
OVERSHOOT expression only based on Velocity - NOT keyframes
on Feb 27, 2020 at 7:05:56 pm

Hi everyone,

I'm working on a project where I have a Null "A" moving with expressions. I have another Null "B" with its position linked to "A". I'd like the position of "B" to "overshoot".

We see many expressions around using the famous overshoot expression from Dan Ebberts but they are ALL using a keyframed animation as reference at some point.
What if, like in my situation, you don't have any keyframes! Could it be possible to make an overshoot expression using only the velocity (for instance) of a property? Is this even possible?

Have a great day


Return to posts index

Dan Ebberts
Re: OVERSHOOT expression only based on Velocity - NOT keyframes
on Feb 27, 2020 at 7:40:00 pm

You could, but the expression would have to know when to pick up the velocity. What determines when Null A stops its motion?

Dan



Return to posts index

Remi Monedi
Re: OVERSHOOT expression only based on Velocity - NOT keyframes
on Feb 27, 2020 at 9:39:40 pm

Nothing in particular since I was thinking of the most versatile expression (the position of "A"could be set with expressions, another layer, keyframes). This is why I thought of its velocity as the main reference for its motion.

The expression you're talking about Dan, it can't watch for the velocity during the whole composition?


Return to posts index


Dan Ebberts
Re: OVERSHOOT expression only based on Velocity - NOT keyframes
on Feb 27, 2020 at 9:49:12 pm

What you want is the velocity when the force is removed. For example, with this expression:

easeIn(time,0,1,[0,0],[500,500]);

You'd want to sample the velocity at 0.999 sec (right before the layer stops moving).

Dan



Return to posts index

Remi Monedi
Re: OVERSHOOT expression only based on Velocity - NOT keyframes
on Feb 28, 2020 at 11:36:00 am

To calculate the velocity I found several methods, I tried them all and got to those conclusions :
The difference : property-property.valueAtTime(time-.01)
The velocityAtTime(), but I couldn't get it to work with a property, maybe this is my mistake.
The .speed function, simple enough, I chose this one.

Then I tried to tweak your overshoot expression Dan, this time, with a property of only 1 array, the Rotation of Null "A" (to make things easier).
Here is the expression of the Rotation of Null "A" :

linear(time,0,0.1,0,180);

And the expression of the rotation of Nul "B" :

// ----- REFERENCE PROPERTY -----
ref = thisComp.layer("A").transform.rotation;
refvelocity = ref.speed

// ----- OVERSHOOT -----
freq = 3;
decay = 5;

t = time - inPoint;
dur = 0.1;
if (refvelocity != 0){
ref
}else{
amp = 180/dur;
w = freq*Math.PI*2;
ref + amp*(Math.sin((t-dur)*w)/Math.exp(decay*(t-dur))/w);
}


It works but I have 2 problems to fully "automate" this expression, mainly because when it comes to time in expression, I'm very quickly lost :

1. the duration of the animation "dur" is a value, but it could be :
dur = Moment when "refvelocity" change its value back to 0 (end of a movement) - Moment when "refvelocity" change its value to something different than 0 (start of a movement)


2. the amplitude "amp" is a value too but it could be
amp = Value of "ref" when "refvelocity" change its value back to 0 - Value of "ref" when "refvelocity" change its value to something different than 0


Is it possible to get those informations?
If yes, which expression should I use, or how you should I write it?


Return to posts index

Remi Monedi
Re: OVERSHOOT expression only based on Velocity - NOT keyframes
on Feb 28, 2020 at 1:17:27 pm

I found this expression used in Duik from Rainboxprod : instead of using keyframes it uses the anchorpoint Position of the target layer which is parented to another one to overshoot its position.BUT it only works for Position and Anchorpoint.

I tried to modify this expression to fit my needs :
Instead of having a target layer "B" parented to another layer "A" and the position of "B" being "overshot" by the movement of "A", I want to have any property (position, scale, rotation, ...) of "B" linked to the same properties of "A" and being overshot as the properties of "A" change.
But without success...

I think the key is somewhere in these lines of code :

worldVelocityX = (thisLayer.toWorld(thisLayer.anchorPoint,TIME)[0]-thisLayer.toWorld(thisLayer.anchorPoint,TIME-.01)[0])*100;
worldVelocityY = (thisLayer.toWorld(thisLayer.anchorPoint,TIME)[1]-thisLayer.toWorld(thisLayer.anchorPoint,TIME-.01)[1])*100;


But I cannot make it work with other properties than anchorpoint. Maybe this is because of my misunderstanding of Speed VS Velocity and how it applies in the world of expression.

Could this expression be adapted to fit my needs, or should I go with the first one I was trying to adapt?

decay = 5;
freq = 3;
if (decay == 0) decay = 0.1;
if (freq == 0) freq = 0.1;
delay = freq/decay;
weight = 1/decay/10;
frameDur = thisComp.frameDuration;
function worldVelocity(TIME) {
worldVelocityX = (thisLayer.toWorld(thisLayer.anchorPoint,TIME)[0]-thisLayer.toWorld(thisLayer.anchorPoint,TIME-.01)[0])*100;
worldVelocityY = (thisLayer.toWorld(thisLayer.anchorPoint,TIME)[1]-thisLayer.toWorld(thisLayer.anchorPoint,TIME-.01)[1])*100;
return [worldVelocityX,worldVelocityY];
}
function worldSpeed(TIME) {
return length(worldVelocity(TIME));
}
timeStart = 0;
timeRestart = 0;
stop = false;
stopped = false;
for (i=timeToFrames(time);i>=0;i--) {
var t = framesToTime(i);
var tNext = t-frameDur;
if (worldSpeed(t) == 0 ) {
if (timeRestart == 0) timeRestart = t;
if (worldSpeed(tNext) !=0 ) {
timeStart = tNext;
break;
}
}
}
TIME = time-timeStart;
frameRestart = timeToFrames( time-timeRestart);
w = value
if ( frameRestart &lt;= delay)
w = value - worldVelocity(time)*weight*(frameRestart/delay);
else
w = value - worldVelocity(time)*weight;
if (worldSpeed(time) == 0) {
spring = worldVelocity(timeStart) * ( .15/freq * Math.sin(freq * TIME * 2 * Math.PI) / Math.exp( TIME * decay ) );
w + spring;
}else{ w; }


Return to posts index


Remi Monedi
Re: OVERSHOOT expression only based on Velocity - NOT keyframes
on Feb 28, 2020 at 4:43:37 pm

Ok, I find a way to adapt this expression to my need. I wasn't familiar with the .toWorld function.
I replaced the 2 lines I was talking earlier by these 2 and it works fine.

worldVelocityX = (thisComp.layer("A").toWorld(thisComp.layer("A").position,TIME)[0]-thisComp.layer("A").toWorld(thisComp.layer("A").position,TIME-.01)[0])*100;
worldVelocityY = (thisComp.layer("A").toWorld(thisComp.layer("A").position,TIME)[1]-thisComp.layer("A").toWorld(thisComp.layer("A").position,TIME-.01)[1])*100;


Now, no matter how the position of a layer "A" is animated, the position of the layer "B" will follow it with an "overshoot" trajectory. Yay!

But clearly, I don't understand how it works. And I think this expression is only for 2D position parameter. I don't think it could apply for Rotation or scale (there is length function on line 14). Where the previous expression from Dan was simpler and shorter even if I missed some elements to make it perfectly automated.

SO, I'm still wondering if I can "automate" the overshoot expression from Dan, OR if this long expression from Duik is better for what I want.
Any thoughts?

decay = 5;
freq = 3;
if (decay == 0) decay = 0.1;
if (freq == 0) freq = 0.1;
delay = freq/decay;
weight = 1/decay/10;
frameDur = thisComp.frameDuration;
function worldVelocity(TIME) {
worldVelocityX = (thisComp.layer("A").toWorld(thisComp.layer("A").position,TIME)[0]-thisComp.layer("A").toWorld(thisComp.layer("A").position,TIME-.01)[0])*100;
worldVelocityY = (thisComp.layer("A").toWorld(thisComp.layer("A").position,TIME)[1]-thisComp.layer("A").toWorld(thisComp.layer("A").position,TIME-.01)[1])*100;
return [worldVelocityX,worldVelocityY];
}
function worldSpeed(TIME) {
return length(worldVelocity(TIME));
}
timeStart = 0;
timeRestart = 0;
stop = false;
stopped = false;
for (i=timeToFrames(time);i>=0;i--) {
var t = framesToTime(i);
var tNext = t-frameDur;
if (worldSpeed(t) == 0 ) {
if (timeRestart == 0) timeRestart = t;
if (worldSpeed(tNext) !=0 ) {
timeStart = tNext;
break;
}
}
}
TIME = time-timeStart;
frameRestart = timeToFrames( time-timeRestart);
w = value
if ( frameRestart &lt;= delay)
w = value - worldVelocity(time)*weight*(frameRestart/delay);
else
w = value - worldVelocity(time)*weight;
if (worldSpeed(time) == 0) {
spring = worldVelocity(timeStart) * ( .15/freq * Math.sin(freq * TIME * 2 * Math.PI) / Math.exp( TIME * decay ) );
w + spring + thisComp.layer("A").transform.position;
}else{ w + thisComp.layer("A").transform.position; }


Return to posts index

<< PREVIOUS   •   VIEW ALL   •   PRINT   •   NEXT >>
© 2020 CreativeCOW.net All Rights Reserved
[TOP]