是否有公式将AccelerationRatio或DecelerationRatio转换为贝塞尔控制点,以便在KeySpline
的{{1}}中使用?例如,“缓出”可能是SplineDoubleKeyFrame
,但这似乎与DecelerationRatio=0.5
或KeySpline="0.0,0.0 0.5,1.0"
不等。
这会涉及多个KeySpline="0.5,0 1,0.5"
来实现SplineDoubleKeyFrame
吗?或者他们是一个特殊的公式,使他们在一个框架中等效?
或者这不是通过DecelerationRatio=0.5
而是通过SplineDoubleKeyFrame
来实现的(如果是,那么EasingFunction / EasingMode /其他属性是什么)?
基本上,我正在尝试使用KeyFrames实现EasingDoubleKeyFrame
,因为会有多个帧定位到相同的属性路径并加速/减速它。
更新:根据第7页的Microsoft WPF-Silverlight Comparison Whitepaper.pdf:
线性插值 可以通过添加稍微修改 AccelerationRatio和 DecelerationRatio属性为 动画。这些属性 基本上创建三个线性 整个插值 动画为了修改 启动和停止速度。对于 例如,设计师会使用这些 属性逐渐拥有一个对象 提速或突然停止。 不幸的是,Silverlight没有 实现这两个属性,但是 效果可以重复使用 具有线性插值的关键帧动画。
所以我猜这意味着可以只用3个关键帧完成,但公式是什么我不知道。
解决方案:对于其他可能需要的人,发布由Peter Taylor制作的ECMAScript解决方案:
<DoubleAnimation Storyboard.TargetName="deceleratedRectangle" Storyboard.TargetProperty="(Rectangle.Width)" DecelerationRatio="0.5" Duration="0:0:10" From="20" To="400" />
答案 0 :(得分:8)
更新:使用微积分的几何解释作为一条线下的区域,我已经研究了如何简化推导。
因此,我们在时间t0从y0插入到时间t1的y1,加速比ra和减速比rd。比率的定义给出了我们停止加速的时间,ta = t0 + ra *(t1-t0),并且我们开始减速,td = t1-rd *(t1-t0)。
我理解你引用的文件是指从t0到ta的恒定加速度,以及从td到t1的恒定减速度。我们将达到的最大速度为vm。
Speed | _____________________________________ vm + /| |\ | / \ | / | | \ | / \ | / | | \ | / \ | / | | \ |/ \ +--------+-----------------------------------+--------+---- Time t0 ta td t1
然后平行四边形的面积是从t0到t1的距离,即y1-y0。平行四边形的面积是高度与平行边的平均值的乘积。所以
y1 - y0 = vm *((t1 - t0)+(td - ta))/ 2
或
vm = 2 *(y1 - y0)/(t1 + td - ta - t0)
只使用末尾三角形的区域,我们可以找到当我们停止加速时我们走了多远,ya = y(ta),当我们开始减速时,yd = y(td)。
ya = y0 + vm *(ta - t0)/ 2
yd = y1 - vm *(t1 - td)/ 2
最后,我们为[t0,ta],直线(ta,ya) - (td,yd)生成二次Bezier,为[td,t1]生成二次Bezier。
对于第一个Bezier,我们有明显的控制点P0 =(t0,y0)和P2 =(ta,ya)。为了找到P1,我们使用P0-P1与曲线相切并且P1-P2与曲线相切的属性(通常,对于阶数-n曲线,P0-P1和P(n-1)-Pn是相切的) 。因此P1位于y = y0与中段直线的交点处。类似地,对于另一个贝塞尔:Q0 =(td,yd),Q2 =(t1,y1),Q1位于y = y1与中段直线的交点处。
没有淡入(加速比= 0),减速比= 0.5,t0 = 0,t1 = 10(秒),y0 = 20,y1 = 400.我认为这符合您的具体问题。
ta = 0(我们可以省略第一个二次贝塞尔曲线); td = t1 - 0.5 *(t1 - t0)= 5.
vm = 2 *(y1 - y0)/(t1 + td - ta - t0)= 2 *(400 - 20)/(10 + 5 - 0 - 0)= 2 * 380/15 = 152/3 〜= 50.67。
忽略你,因为我们正在跳过Bezier。
yd = y1 - vm *(t1 - td)/ 2 = 400 - 152/3 *(10-5)/ 2 = 400 - 380/3 = 820 / 3~ = 273.3
因此直线从(t = 0,y = 20)变为(t = 5,y = 273.3)。减速Bezier的Q0 =(5,273.3),Q2 =(10,400)。
为了找到Q1,我们将直线延伸到y = 400。该线具有方程y - 20 =(t - 0)*(273.3 - 20)/(5 - 0),因此t = 5 *(400 - 20)/(273.3 - 20)= 7.5。
所以我们有直线(0,20) - (5,273.3)和带控制点(5,273.3),(7.5,400)和(10,400)的二次贝塞尔曲线。
然而,有一个轻微的障碍,这是微软没有设计给我们二次样条。我们必须将二次Q0,Q1,Q2提升到立方Q0,(Q0 + 2 Q1)/ 3,(2 Q1 + Q2)/ 3,Q2。
我们还必须将控制点重新调整为0-1。如果我们首先应用重新缩放,我们有(0,0) - (0.5,1) - (1,1)。所以立方是(0,0) - (0.333,0.667) - (0.667,1) - (1,1)。
我知道样条,但不知道WPF。我认为以下会做你想做的事:
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="20" /> <LinearDoubleKeyFrame KeyTime="0:0:5" Value="273.333" /> <SplineDoubleKeyFrame KeyTime="0:0:10" Value="400" KeySpline="0.333,0.667,0.667,1"/>
重新缩放第一个贝塞尔曲线,我们将(t0,y0)映射到(0,0)和(ta,ya)到(1,1)。因此,我们将(P1.t,P1.y)映射到((P1.t-t0)/(ta-t0),(P1.y-y0)/(ya-y0))。但是P1在y = y0与梯度直线vm到(ta,ya)的交点处,因此具有方程(y-ya)=(t-ta)* vm。所以P1.y = y0和P1.t = ta +(y0-ya)/ vm = ta - (ya-y0)/ vm。插入我们的身份ya = y0 + vm *(ta - t0)/ 2,得到P1.t = ta - (vm *(ta - t0)/ 2)/ vm = ta - (ta - t0)/ 2 = (ta + t0)/ 2。
如此重新缩放我们将P1映射到(0.5,0)。因此,当我们将其提升为三次贝塞尔曲线时,中间控制点始终为(1 / 3,0)和(2 / 3,1 / 3)。
同样,减速样条曲线的缩放中间点始终为(1 / 3,2 / 3)和(2 / 3,1)。
答案 1 :(得分:2)
我希望我的问题是对的。
我在WPF项目中测试了您的示例,并使用DoubleAnimationUsingKeyFrames和SplineDoubleKeyFrame创建了类似的效果。这是我在故事板中所做的(这是减速):
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" Storyboard.TargetName="rectangle">
<SplineDoubleKeyFrame KeyTime="0" Value="1"/>
<SplineDoubleKeyFrame KeyTime="0:0:3" Value="3.45" KeySpline="0,0.52,0.51,1"/>
</DoubleAnimationUsingKeyFrames>
诀窍是为SplineDoubleKeyFrame设置Bezier。如果您想要平滑的加速/减速,请尝试使用更接近线性形式的贝塞尔曲线。
此外:Acceleration / DecelerationRatio适用于整个动画,但KeySpline仅适用于KeyFrame。如果您有一个由多个KeyFrame组成的动画,请考虑这一点。