开发者

Animation with Initial Velocity

开发者 https://www.devze.com 2022-12-25 21:10 出处:网络
I\'ve been trying to solve this problem for a number of days now but I must be missing something. Known Variables:

I've been trying to solve this problem for a number of days now but I must be missing something.

Known Variables:

vi = Initial Velocity

t = Animation Duration

d = Distance.

end velocity should always be zero

The function I'm trying to create: D(0...t) = the current distance for a given time

Using this information I want to be able to create a smooth animation curve with varying velocity (ease-in/ease-out).

The animation must be able ease-in from an initial velocity.

The animation must be exactly t seconds and must be travel exactly d units.

The curve should lean towards the average velocity with acceleration occurring at the beginning and the end portions of the curve.

I'm open to 开发者_JAVA技巧extra configuration variables.

The best I've been able to come up with is something that doesn't factor in the initial velocity. I'm hoping someone smarter can help me out. ;)

Thank you!

p.s. I'm working with an ECMAScript variant


Here is a different solution, where there isn't any time interval where the velocity is constant. Instead, velocity as a function of time is a second-order polynomial, and the acceleration is linear in time (positive at the beginning, and negative at the end). Maybe you can try it.

Let me rename your variables a bit. Let

  • T = final time = animation duration
  • V = initial velocity (>0)
  • D = total distance (>0)

We are searching for a smooth function v(t) (velocity as a function of time) such that:

  • v(0) = V
  • v(T) = 0
  • the integral from 0 to T of v(t)dt is D

With a (concave) second-order polynomial we can satisfy all the three constraints. Hence, let

v(t) := at^2 + bt + c

and let's solve for a, b, c. The first constraint v(0) = V gives immediately c = V. The second constraint reads

aT^2 + bT + V = 0

On the other hand, the integral of v(t) is d(t) = 1/3 a t^3 + 1/2 b t^2 + Vt (this is the distance covered up to time t), hence the third constraint reads

d(T) = 1/3 a T^3 + 1/2 b T^2 + VT = D

The last two equations seem messy, but they are just two linear equations in the two unknowns a, b, and they should be easily solvable. If I did my computations correctly, the final result is

a = 3V/T^2 - 6D/T^3, b = 6D/T^2 - 4V/T

If you substitute a, b, c in the expression of d(t), you obtain the covered distance as a function of time.


I believe you want to solve your problem in 3 parts.

First, you need to solve for the minimum velocity necessary to complete the distance in time T.

This would be pretty simple (D/t) = v(min)

It assumes instantaneous acceleration from v(initial) to v(min) and again deceleration over a time period of 0s at the beginning and end.

so for example say your v(i) is 5px/s. you want a 100px movement over 10 seconds.

v(min) = 100px/10s = 10px/s

Second, you want a smooth acceleration from v(initial) to v(min). this will take some period of time t(acc). Assuming the acceleration and deceleration will be equal, then you can just figure for one of them, then multiply by 2. We can call the function that describes the distance travelled during accelleration D(accel).

Lets keep it easy to start and say we want the duration of accelleration to be 1s

so your equation for total distance travelled is going to be D(total) = D(accel) + D(v(max) )

When you know that D(accel) is for 2s total, you can calculate

D(accel) = ( V(ini) + V(max) ) /2) * (2seconds)

and

D(v(max)) = V(max) * 8s

solving for V(max) we get

100px = D(accel) + D(v(max))

100px = ( 5px/s + VMax) /2 *(2s)) + VMax *8s

100px = 5px + (Vmax * 1s) + Vmax *8s

95px = 9Vmax *s

VMax = 95px/9s

VMax = 10.556px/s

You can now go back and replace your 1s acceleration window with a formula that defines the acceleration window as a % of the overall time period or some other thing.

Also note that for animation purposes, you will have to break 10.556px/s down into per frame px movements and account for time appropriately.


abustin, since you don't like the 3 segment solution, you may want to try looking at Bezier curves to solve this problem. Bezier curve can be utilized to interpolate time as well as distance, so you can define a few control points near the ends of your motion to generate acceleration, where the middle "segment" will be defined such that the velocity is close to constant. Utilizing splines is a possibility too.


Using constant accelerations:

Definitions:

Vi - Initial velocity
Va - Average velocity
Vo - Ending velocity
D  - Total distance to be traveled
T  - Total time for travel
t1 - Acceleration time from beginning to Va
t2 - Acceleration time from Va to Vo

The equation to solve is:

(Vi+Va)/2*t1 + Va*(T-t2-t1) + (Va+Vo)/2*t2 = D

You should decide how much time the initial acceleration (t1) and the final acceleration (t2) takes and then you are left with only one unknown -> Va, which can be easily solved.

EDIT: find the distance as a function of time:

Well, now that you know the velocities, it is easy to figure out the distance traveled:

D(t) = Vi*t + 0.5*t^2*(Va-Vi)/t1                {0<t<t1}
D(t) = Va*(t-t1) + D1                           {t1<t<t3}
D(t) = Va*(t-t3)+0.5*(t-t3)^2*(Vo-Va)/t2 + D2   {t3<t<T}

where t3=(T-t2), D1 and D2 are the distance traveled at the end of the first and second segments, which can be found from the respective functions:

D1 = 0.5*(Va+Vi)*t1
D2 = D1 + Va*(t3-t1)

EDIT 2: Solving for Va:

(Vi+Va)/2*t1 + Va*(T-t2-t1) + (Va+Vo)/2*t2 = D

Remember that t1 and t2 are the problem parameters that you choose. You decide what fraction of the movement the object accelerates and decelerates. Let's say t1=t2=0.1*T. Substitution then gives:

(Vi+Va)/2*(0.1T) + Va*(T-(0.1T)-(0.1T)) + (Va+Vo)/2*(0.1T) = D
Va*(0.1T/2 + T-0.1T-0.1T + 0.1T/2) + Vi*(0.1T)/2 + Vo*(0.1T)/2 = D
Va*(0.9T) + Vi*(0.05T) + Vo*(0.05T) = D
Va*(0.9T) = D - Vi*(0.05T) + Vo*(0.05T)
Va = (D - (Vi + Vo)*(0.05T)) / (0.9T)

Got it?


Federico's solution is a nice one, but I found the acceleration of a linear acceleration solution a bit too abrupt, and I ended up forging ahead with a double parabola solution where the acceleration is constant, first in one direction and then in the other, until the object ends at 1 with a velocity 0. (I did try solving it with variable starts and ends, but it was too difficult. Instead, my implementation just scales the inputs and outputs before passing them through the function.)

The math was high school stuff, but I'll go over it for completeness' sake.

given v, the initial velocity, we have two parabolas, the left and the right

  • ly = m(t - ax)^2 + ay, where t is the time input, ranging from 0 to 1, and ax, ay, and m are constants we need to find, given v.
  • ry = -m(t - 1)^2 + 1

Note, they both take m as their steepness, because they accelerate at the same rate. ry uses -m because it accelerates in the other direction.

We have a number of constraints to solve for

  • ly(0) = 0, the value is 0 at t = 0
  • ly'(0) = v, the differential of the equation(the velocity) is v(the initial velocity, given) at t = 0
  • ly(h) = ry(h), the two parabolas connect at some given halfway point (which is not actually halfway unless v = 0)
  • ly'(h) = ry'(h), the velocity is the same at that halfway point, no sudden jerks

I went through a number of approaches from here on out, but in the end it seemed that the only way was to solve for m in terms of v. We arrive at the formula mm + m(v - 2) - (vv)/4. Applying the quadratic formula, we get m = ((2 - v) ± sqrt(2vv - 4v + 4))/2 Meaning that either

m = ((2 - v) + sqrt(2v*v - 4v + 4))/2

or

m = ((2 - v) - sqrt(2v*v - 4v + 4))/2

And we find that we can decide which it is by looking at the initial velocity,

let sqrt_part = Math.sqrt(2*sq(initial_velocity) - 4*initial_velocity + 4)
let m = (2 - initial_velocity + (initial_velocity < 2 ? sqrt_part : -sqrt_part))/2

from there, the rest of the variables (ax, ay and h) are quite easy to work out.

There is a rust implementation of the formulai here https://gist.github.com/makoConstruct/df173c3a4e0854b535869fdc2acdeeb1

Rust's syntax is pretty ordinary, so you wont have much trouble translating that to JS. Feel free to post your port in the comments.

0

精彩评论

暂无评论...
验证码 换一张
取 消