我一直试图解决这个问题好几天了,但我一定错过了什么。
已知变量:
vi =初始速度
t =动画持续时间
d =距离。
结束速度应始终为零
我正在尝试创建的函数: D(0 ... t)=给定时间的当前距离
使用此信息,我希望能够以不同的速度创建平滑的动画曲线(缓入/缓出)。
动画必须能够从初始速度轻松进入。
动画必须正好是t秒,并且必须精确到达d个单位。
曲线应该倾向于平均速度,加速发生在曲线的开始和结束部分。
我愿意接受额外的配置变量。
我能想出的最好的东西不会影响初始速度。我希望更聪明的人可以帮助我。 ;)
谢谢!
P.S。我正在使用ECMAScript变体
答案 0 :(得分:5)
这是一个不同的解决方案,其中没有任何时间间隔,其中速度是恒定的。相反,作为时间函数的速度是二阶多项式,并且加速度在时间上是线性的(开始时为正,末端为负)。也许你可以尝试一下。
让我稍微重命名你的变量。让
我们正在寻找平滑函数v(t)(作为时间函数的速度),以便:
使用(凹)二阶多项式,我们可以满足所有三个约束。因此,让
v(t):= at ^ 2 + bt + c
让我们解决a,b,c。第一个约束v(0)= V立即给出c = V。 第二个约束条件为
aT ^ 2 + bT + V = 0
另一方面,v(t)的积分是d(t)= 1/3 at ^ 3 + 1/2 bt ^ 2 + Vt(这是到时间t所覆盖的距离),因此第三个约束读取
d(T)= 1/3 a T ^ 3 + 1 / 2b T ^ 2 + VT = D
最后两个方程似乎很混乱,但它们只是两个未知数a,b中的两个线性方程,它们应该很容易解决。如果我正确地进行了计算,最终的结果是
a = 3V / T ^ 2 - 6D / T ^ 3,b = 6D / T ^ 2 - 4V / T
如果在d(t)的表达式中替换a,b,c,则获得覆盖距离作为时间的函数。
答案 1 :(得分:1)
我相信你想分三个部分解决你的问题。
首先,您需要求出完成时间距离T所需的最小速度。
这很简单(D / t)= v(min)
假设从v(初始)到v(min)的瞬时加速,并在开始和结束时在0s的时间段内再次减速。
所以例如说你的v(i)是5px / s。 你希望在10秒内完成100px的运动。
v(min)= 100px / 10s = 10px / s
其次,您需要从v(初始)到v(min)的平滑加速。这将需要一段时间t(acc)。假设加速度和减速度相等,那么你可以只计算其中一个,然后乘以2。 我们可以调用描述加速D(加速度)期间行进距离的函数。
让我们保持开始,并说我们希望加速的持续时间为1秒
所以你的总行程距离的等式将是 D(总)= D(加速度)+ D(v(max))
当您知道D(加速度)总计为2秒时,您可以计算
D(加速度)=(V(ini)+ V(最大值))/ 2)*(2秒)
和
D(v(max))= V(max)* 8s
求解V(max)得到
100px = D(加速度)+ 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
您现在可以返回并使用公式替换1s加速窗口,该公式将加速窗口定义为整个时间段的百分比或其他内容。
另请注意,出于动画目的,您必须将10.556px / s分解为每帧px移动并适当考虑时间。
答案 2 :(得分:0)
使用恒定加速度:
说明:
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
要解决的等式是:
(Vi+Va)/2*t1 + Va*(T-t2-t1) + (Va+Vo)/2*t2 = D
您应该确定初始加速度(t1)和最终加速度(t2)花费的时间,然后只留下一个未知的时间 - > Va,可以轻松解决。
编辑:找到距离作为时间的函数:
嗯,既然您知道速度,就很容易弄清楚行进的距离:
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}
其中t3 =(T-t2),D1和D2是第一段和第二段末端的行进距离,可以从各自的函数中找到:
D1 = 0.5*(Va+Vi)*t1
D2 = D1 + Va*(t3-t1)
编辑2 :解决Va:
(Vi+Va)/2*t1 + Va*(T-t2-t1) + (Va+Vo)/2*t2 = D
请记住,t1和t2是您选择的问题参数。您可以决定物体加速和减速的运动比例。假设t1 = t2 = 0.1 * T.替换然后给出:
(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)
知道了吗?
答案 3 :(得分:0)
abustin,因为您不喜欢3段解决方案,您可能需要尝试查看Bezier curves来解决此问题。贝塞尔曲线可用于插值时间和距离,因此您可以在运动末端附近定义一些控制点以生成加速度,其中将定义中间“段”以使速度接近常数。也可以使用splines。
答案 4 :(得分:0)
Federico的解决方案很好,但我发现线性加速解决方案的加速度有点过于突然,我最终用双抛物线解决方案向前推进,其中加速度是恒定的,首先在一个方向然后在另外,直到对象以1的速度结束,速度为0.(我确实尝试用变量开始和结束来解决它,但这太难了。相反,我的实现只是在将输入和输出传递给函数之前对其进行缩放。)< / p>
数学是高中的东西,但为了完整起见,我会完成它。
给定v,初始速度,我们有两个抛物线,左边和右边请注意,他们都将m视为陡峭,因为它们以相同的速度加速。使用-m因为它在另一个方向加速。
我们有许多要解决的限制
我从现在开始经历了许多方法,但最后似乎唯一的方法就是用v来解决m。我们得到的公式为mm + m(v - 2) - ( VV)/ 4。应用二次公式,我们得到m =((2 - v)±sqrt(2vv - 4v + 4))/ 2 意思是
m =((2 - v)+ sqrt(2v * v - 4v + 4))/ 2
或
m =((2 - v) - sqrt(2v * v - 4v + 4))/ 2
我们发现我们可以通过查看初始速度来确定它是什么,
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
从那里开始,其余变量(ax,ay和h)很容易解决。
这里的公式https://gist.github.com/makoConstruct/df173c3a4e0854b535869fdc2acdeeb1
有一个生锈实现Rust的语法非常普通,因此将它转换为JS时不会有太多麻烦。您可以在评论中发布您的端口。