弹簧 - 质量系统的阻尼效应(或者是弹性系统?)

Tod*_*ain 12 silverlight wpf animation physics

我试图在代码中模拟动画效果(几乎任何语言都可以,因为它似乎是数学而不是语言).从本质上讲,它是质量弹簧系统的仿真.我一直在看WPF/Silverlight ElasticEase,这看起来非常接近我正在寻找的东西,但并不完全.

首先,这里就是我要找的-一个对象,旅游若干秒,创下了位置,并立即下降放缓至ocsillate一定的秒数在涂敷阻尼的相同点休息.所以为了想象这个,让我说我有一个600w/900h的画布,我有一个正方形,开始动画从900px到150px TranslateTransform.Y.它需要4秒内达到150像素高度(每秒187.5px),在该阶段它被immediated阻尼并且仅行进大约35px更0.4秒(每秒87.5px)至115px高度,然后向下篮板1秒至163px高度(48px和48px每秒),然后回升到146px(17px和17px每秒),依此类推,直到ocillations减慢到最后150px的休息位置.ocirlation时间是16秒.

我上面描述的例子是左上角的蓝色矩形: 在此输入图像描述

这是我事先知道的 - 像素距离和从A点到B点所需的秒数,即ocirlation的秒数.像质量这样的东西似乎并不重要.

我已经尝试ElasticEase了,问题似乎是我无法让对象在没有缓和4秒的情况下旅行,然后在接下来的16秒内"反弹".该.Springiness也总是太多,即使我将其设置为像20一个非常高的数字.

ILSpy展示其功能如下:

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);
        }
Run Code Online (Sandbox Code Playgroud)

我在DropBox的压缩文件夹中包含了2个视频和一个Excel文件.我想这个问题将更多的是正在进行的工作,因为人们会提出更多澄清问题.

(免责声明:当涉及到大部分内容时,我不知道我在谈论什么)

tom*_*m10 9

跳过物理学,然后直接进入等式.

参数:"这是我事先知道的 - 像素距离[D]和从A点到B点所需的秒数[T0],振荡的秒数[T1]."另外,我ll作为自由参数添加:振荡的最大大小,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)
Run Code Online (Sandbox Code Playgroud)

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

在此输入图像描述

笔记:

  1. 评论中的大多数人都在提出物理方法.我没有使用这些,因为如果一个人指定某个动作,那么从物理学开始,转到微分方程,然后计算运动,并调整参数以获得最终结果.不妨直接去做最后的事情.除非,即一个人对他们想要工作的物理学有直觉.
  2. 通常在这样的问题中,人们希望保持连续的速度(一阶导数),但是你说"立即减速",所以我没有在这里做到这一点.
  3. 请注意,振动的周期和振幅不会与施加阻尼时的指定完全一致,但这可能比您关心的更详细.
  4. 如果您需要将其表示为单个等式,则可以使用"Heaviside函数"来执行此操作,以打开和关闭贡献.

冒这么长的风险,我意识到我可以在GIMP中制作一个gif,所以这就是它的样子:

在此输入图像描述

如果有兴趣的话,我可以发布完整的代码来制作图,但基本上我只是为每个时间步用不同的D和T0值调用Y. 如果我再次这样做,我可以增加阻尼(即减少Tc),但这有点麻烦,所以我将其保留原样.


Pet*_*lor 5

我和@ tom10一样思考着.(我也考虑IEasingFunction了一个IList<IEasingFunction>,但是从现有的行为中破解所需的行为会很棘手).

// Based on the example at
// http://msdn.microsoft.com/en-us/library/system.windows.media.animation.easingfunctionbase.aspx
namespace Org.CheddarMonk
{
    public class OtakuEasingFunction : EasingFunctionBase
    {
        // The time proportion at which the cutoff from linear movement to
        // bounce occurs. E.g. for a 4 second movement followed by a 16
        // second bounce this would be 4 / (4 + 16) = 0.2.
        private double _CutoffPoint;
        public double CutoffPoint {
            get { return _CutoffPoint; }
            set {
                if (value <= 0 || value => 1 || double.IsNaN(value)) {
                    throw new ArgumentException();
                }
                _CutoffPoint = value;
            }
        }

        // The size of the initial bounce envelope, as a proportion of the
        // animation distance. E.g. if the animation moves from 900 to 150
        // and you want the maximum bounce to be no more than 35 you would
        // set this to 35 / (900 - 150) ~= 0.0467.
        private double _EnvelopeHeight;
        public double EnvelopeHeight {
            get { return _EnvelopeHeight; }
            set {
                if (value <= 0 || double.IsNaN(value)) {
                    throw new ArgumentException();
                }
                _EnvelopeHeight = value;
            }
        }

        // A parameter controlling how fast the bounce height should decay.
        // The higher the decay, the sooner the bounce becomes negligible.
        private double _EnvelopeDecay;
        public double EnvelopeDecay {
            get { return _EnvelopeDecay; }
            set {
                if (value <= 0 || double.IsNaN(value)) {
                    throw new ArgumentException();
                }
                _EnvelopeDecay = value;
            }
        }

        // The number of half-bounces.
        private int _Oscillations;
        public int Oscillations {
            get { return _Oscillations; }
            set {
                if (value <= 0) {
                    throw new ArgumentException();
                }
                _Oscillations = value;
            }
        }

        public OtakuEasingFunction() {
            // Sensible default values.
            CutoffPoint = 0.7;
            EnvelopeHeight = 0.3;
            EnvelopeDecay = 1;
            Oscillations = 3;
        }

        protected override double EaseInCore(double normalizedTime) {
            // If we get an out-of-bounds value, be nice.
            if (normalizedTime < 0) return 0;
            if (normalizedTime > 1) return 1;

            if (normalizedTime < _CutoffPoint) {
                return normalizedTime / _CutoffPoint;
            }

            // Renormalise the time.
            double t = (normalizedTime - _CutoffPoint) / (1 - _CutoffPoint);
            double envelope = EnvelopeHeight * Math.Exp(-t * EnvelopeDecay);
            double bounce = Math.Sin(t * Oscillations * Math.PI);
            return envelope * bounce;
        }

        protected override Freezable CreateInstanceCore() {
            return new OtakuEasingFunction();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是未经测试的代码,但如果有问题,调试应该不会太糟糕.我不确定需要将哪些属性(如果有的话)添加到XAML编辑器的属性中才能正确处理它们.