Creative Communities of the World Forums

The peer to peer support community for media production professionals.

Forums Adobe After Effects Expressions OVERSHOOT expression only based on Velocity – NOT keyframes

  • OVERSHOOT expression only based on Velocity – NOT keyframes

  • Remi Monedi

    February 27, 2020 at 7:05 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

  • Dan Ebberts

    February 27, 2020 at 7:40 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

  • Remi Monedi

    February 27, 2020 at 9:39 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?

  • Dan Ebberts

    February 27, 2020 at 9:49 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

  • Remi Monedi

    February 28, 2020 at 11:36 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?

  • Remi Monedi

    February 28, 2020 at 1:17 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 <= 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; }

  • Remi Monedi

    February 28, 2020 at 4:43 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 <= 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; }

Viewing 1 - 7 of 7 posts

Log in to reply.

We use anonymous cookies to give you the best experience we can.
Our Privacy policy | GDPR Policy