我正在尝试在代码中模拟动画效果(几乎所有语言都可以,因为它似乎是数学而不是语言)。本质上,它是质量 Spring 系统的仿真。我一直在看WPF/Silverlight的ElasticEase,这似乎与我要寻找的非常接近,但并不完全相同。

首先,这就是我要寻找的东西-一个物体,走了一定的几秒钟,撞到一个位置,立即减速了几秒钟,以使其在施加阻尼的同一点静止。因此,要形象化,可以说我有一个600w/900h的 Canvas ,并且有一个正方形,开始在TranslateTransform.Y中从900px变为150px。它需要4秒钟才能达到150像素的高度(每秒187.5像素),在此阶段它立即受到阻尼,仅在0.4秒钟(每秒87.5像素)的情况下再移动约35像素,达到115像素的高度,然后反弹1秒钟,达到163像素的高度(每秒48px和48px),然后回升到146px(每秒17px和17px),依此类推,直到碰撞将其减慢到最终的静止位置150px。阻塞时间为16秒。

我上面描述的示例是此处的左上方蓝色矩形:

这是我预先知道的-像素距离和从点A到点B所需的秒数,即发生遮挡的秒数。像质量这样的事情似乎并不重要。

我已经尝试过ElasticEase,问题似乎是我无法在4秒钟内不放松地移动对象,然后在接下来的16秒钟内“弹跳”。即使我将.Springiness设置为一个非常高的数字(如20),它也总是太多。

ILSpy show的功能如下:

protected override double EaseInCore(double normalizedTime)
        {
            double num = Math.Max(0.0, (double)this.Oscillations);
            double num2 = Math.Max(0.0, this.Springiness);
            double num3;
            if (DoubleUtil.IsZero(num2))
            {
                num3 = normalizedTime;
            }
            else
            {
                num3 = (Math.Exp(num2 * normalizedTime) - 1.0) / (Math.Exp(num2) - 1.0);
            }
            return num3 * Math.Sin((6.2831853071795862 * num + 1.5707963267948966) * normalizedTime);
        }

我在DropBox的压缩文件夹中包括2个视频和一个Excel文件。我猜这个问题将随着人们提出更明确的问题而更多地在进行中。

(免责声明:关于其中大部分内容,我不知道我在说什么)

最佳答案

跳过物理学,直接进入方程式。

参数:
“这是我事先知道的-从点A到点B所需的像素距离[D]和秒数[T0],以及振荡[T1]的秒数。”另外,我将添加为自由参数:振荡的最大大小Amax,阻尼时间常数Tc和帧速率Rf,即在什么时候需要一个新的位置值。我假设您不想永远计算这个,所以我只做10秒,Ttotal,但是有各种合理的停止条件...

代码:
这是代码(在Python中)。最主要的是在def Y(t)中找到的等式:

from numpy import pi, arange, sin, exp

Ystart, D = 900., 900.-150.  # all time units in seconds, distance in pixels, Rf in frames/second
T0, T1, Tc, Amax, Rf, Ttotal = 5., 2., 2., 90., 30., 10.

A0 = Amax*(D/T0)*(4./(900-150))  # basically a momentum... scales the size of the oscillation with the speed

def Y(t):
    if t<T0:  # linear part
        y = Ystart-(D/T0)*t
    else:  # decaying oscillations
        y = Ystart-D-A0*sin((2*pi/T1)*(t-T0))*exp(-abs(T0-t)/Tc)
    return y

y_result = []
for t in arange(0, Ttotal, 1./Rf):  # or one could do "for i in range(int(Ttotal*Rf))" to stick with ints
    y = Y(t)
    y_result.append(y)

这个想法是线性运动到点,然后是衰减的振荡。振荡由sin提供,衰减由exp乘以提供。当然,更改参数以获得所需的任何距离,振荡大小等。

笔记:
  • 评论中的大多数人都在建议物理学方法。我没有使用它们,因为如果指定了某种运动,则从物理学开始,转到微分方程,然后计算运动,并调整参数以获得最终结果,这有点过分了。 。也可以直接进入最后一件事。除非,也就是说,他们对他们要从事的物理学有直觉。
  • 通常在这样的问题中,人们想要保持连续的速度(一阶导数),但是您说“立即减速”,所以我在这里没有这样做。
  • 请注意,施加阻尼时,振荡的周期和幅度将不完全指定,但可能比您关心的要详细。
  • 如果需要将其表示为单个方程式,则可以使用“Heaviside函数”来实现,以打开或关闭作用。

  • 冒着使它变得太长的风险,我意识到我可以在GIMP中制作gif,因此它是这样的:

    如果有兴趣的话,我可以发布完整的代码来绘制图表,但是基本上,我只是在每个时间步使用不同的D和T0值调用Y。如果我要再次执行此操作,则可以增加阻尼(即降低Tc),但这有点麻烦,所以我将其保留。

    关于wpf - Spring 质量系统的阻尼效应(或这是ElasticEase吗?),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7365090/

    10-11 15:52