我正在尝试制作矩阵动画,我同时缩放和转置画布。我发现的唯一方法是使用MatrixTransform和MatrixAnimationUsingKeyFrames。由于似乎没有内置矩阵的任何插值(仅用于路径/旋转),似乎唯一的选择是尝试自己构建插值和DiscreteMatrixKeyFrame。
我做了一个基本的实现,但它并不完全顺利,我不确定这是最好的方法,如何处理帧率等任何人都有改进的建议?这是代码:
MatrixAnimationUsingKeyFrames anim = new MatrixAnimationUsingKeyFrames();
int duration = 1;
anim.KeyFrames = Interpolate(new Point(0, 0), centerPoint, 1, factor,100,duration);
this.matrixTransform.BeginAnimation(MatrixTransform.MatrixProperty, anim,HandoffBehavior.Compose);
public MatrixKeyFrameCollection Interpolate(Point startPoint, Point endPoint, double startScale, double endScale, double framerate,double duration)
{
MatrixKeyFrameCollection keyframes = new MatrixKeyFrameCollection();
double steps = duration * framerate;
double milliSeconds = 1000 / framerate;
double timeCounter = 0;
double diffX = Math.Abs(startPoint.X- endPoint.X);
double xStep = diffX / steps;
double diffY = Math.Abs(startPoint.Y - endPoint.Y);
double yStep = diffY / steps;
double diffScale= Math.Abs(startScale- endScale);
double scaleStep = diffScale / steps;
if (endPoint.Y < startPoint.Y)
{
yStep = -yStep;
}
if (endPoint.X < startPoint.X)
{
xStep = -xStep;
}
if (endScale < startScale)
{
scaleStep = -scaleStep;
}
Point currentPoint = new Point();
double currentScale = startScale;
for (int i = 0; i < steps; i++)
{
keyframes.Add(new DiscreteMatrixKeyFrame(new Matrix(currentScale, 0, 0, currentScale, currentPoint.X, currentPoint.Y), KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(timeCounter))));
currentPoint.X += xStep;
currentPoint.Y += yStep;
currentScale += scaleStep;
timeCounter += milliSeconds;
}
keyframes.Add(new DiscreteMatrixKeyFrame(new Matrix(endScale, 0, 0, endScale, endPoint.X, endPoint.Y), KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(0))));
return keyframes;
}
答案 0 :(得分:3)
试试这个!只要你不旋转/剪切它就可以解决问题。
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;
namespace MapControl
{
public class LinearMatrixAnimation : AnimationTimeline
{
public Matrix? From
{
set { SetValue(FromProperty, value);}
get { return (Matrix)GetValue(FromProperty); }
}
public static DependencyProperty FromProperty = DependencyProperty.Register("From", typeof(Matrix?), typeof(LinearMatrixAnimation), new PropertyMetadata(null));
public Matrix? To
{
set { SetValue(ToProperty, value); }
get { return (Matrix)GetValue(ToProperty); }
}
public static DependencyProperty ToProperty = DependencyProperty.Register("To", typeof(Matrix?), typeof(LinearMatrixAnimation), new PropertyMetadata(null));
public LinearMatrixAnimation()
{
}
public LinearMatrixAnimation(Matrix from, Matrix to, Duration duration)
{
Duration = duration;
From = from;
To = to;
}
public override object GetCurrentValue(object defaultOriginValue, object defaultDestinationValue, AnimationClock animationClock)
{
if (animationClock.CurrentProgress == null)
{
return null;
}
double progress = animationClock.CurrentProgress.Value;
Matrix from = From ?? (Matrix)defaultOriginValue;
if (To.HasValue)
{
Matrix to = To.Value;
Matrix newMatrix = new Matrix(((to.M11 - from.M11) * progress)+from.M11, 0, 0, ((to.M22 - from.M22) * progress)+from.M22,
((to.OffsetX - from.OffsetX) * progress) + from.OffsetX, ((to.OffsetY - from.OffsetY) * progress)+ from.OffsetY);
return newMatrix;
}
return Matrix.Identity;
}
protected override System.Windows.Freezable CreateInstanceCore()
{
return new LinearMatrixAnimation();
}
public override System.Type TargetPropertyType
{
get { return typeof(Matrix); }
}
}
}
答案 1 :(得分:1)
好吧,如果你在MSDN中提出这个问题
http://msdn.microsoft.com/en-us/library/system.windows.media.animation.discretematrixkeyframe.aspx
您将获得DiscreteMatrixKeyFrame导致的答案 突然改变,你应该使用LinearDoubleKeyFrame 或SplineDoubleKeyFrame以及源代码!
编辑:啊,我知道,Matrix转换只支持离散 转换,所以你实际上有跳跃的问题。 所以我建议使用RectAnimationUsingKeyFrames// Create a RectAnimationUsingKeyFrames to
// animate the RectangleGeometry.
RectAnimationUsingKeyFrames rectAnimation = new RectAnimationUsingKeyFrames();
rectAnimation.Duration = TimeSpan.FromSeconds(timeInSeconds);
// Animate position, width, and height in first 2 seconds. LinearRectKeyFrame creates
// a smooth, linear animation between values.
rectAnimation.KeyFrames.Add(
new LinearRectKeyFrame(
new Rect(600,50,200,50), // Target value (KeyValue)
KeyTime.FromTimeSpan(TimeSpan.FromSeconds(2))) // KeyTime
);
// In the next half second, change height to 10.
rectAnimation.KeyFrames.Add(
new LinearRectKeyFrame(
new Rect(600, 50, 200, 10), // Target value (KeyValue)
KeyTime.FromTimeSpan(TimeSpan.FromSeconds(2.5))) // KeyTime
);
只需使用Linear或SplineRectKeyFrame,设置持续时间/关键时间和值即可 需要。要获得比例,您需要计算结束宽度/高度并设置它,但这应该不是问题。
答案 2 :(得分:1)
我已经实现了MatrixAnimation类,它支持平滑的平移,缩放和旋转动画。它还支持缓动功能!找到它here
答案 3 :(得分:1)
我喜欢@LukeN的回答。适用于简单的翻译/缩放动画 我为这段代码添加了缓动(尽管手工制作,而不是WPF原生缓动)。
private double Sigmoid(double v)
{
double t = -6 + (v * 12.0);
return 1.0 / (1.0 + Math.Exp(-t));
}
private double EaseIn(double v)
{
return 2.0 * Sigmoid(v/2.0);
}
private double EaseOut(double v)
{
return 2.0 * ( Sigmoid(0.5 + v/2.0) - 0.5);
}
然后在GetCurrentValue
执行progress = Sigmoid(progress)
或EaseIn(progress)
...
答案 4 :(得分:0)
我能想到的一种方法是将矩阵转换为包含TransformGroup
,ScaleTransform
和RotateTransform
的{{1}},然后使用普通动画为这些动画制作动画,然后,一旦动画完成,再从每个变换中的值创建Matrix?
答案 5 :(得分:0)
如果以后无法访问@pwlodek链接并且不要忘记他的出色课程,我将其复制到SO中:
//http://pwlodek.blogspot.com/2010/12/matrixanimation-for-wpf.html
public class MatrixAnimation : MatrixAnimationBase
{
public Matrix? From
{
set { SetValue(FromProperty, value); }
get { return (Matrix)GetValue(FromProperty); }
}
public static DependencyProperty FromProperty =
DependencyProperty.Register("From", typeof(Matrix?), typeof(MatrixAnimation),
new PropertyMetadata(null));
public Matrix? To
{
set { SetValue(ToProperty, value); }
get { return (Matrix)GetValue(ToProperty); }
}
public static DependencyProperty ToProperty =
DependencyProperty.Register("To", typeof(Matrix?), typeof(MatrixAnimation),
new PropertyMetadata(null));
public IEasingFunction EasingFunction
{
get { return (IEasingFunction)GetValue(EasingFunctionProperty); }
set { SetValue(EasingFunctionProperty, value); }
}
public static readonly DependencyProperty EasingFunctionProperty =
DependencyProperty.Register("EasingFunction", typeof(IEasingFunction), typeof(MatrixAnimation),
new UIPropertyMetadata(null));
public MatrixAnimation()
{
}
public MatrixAnimation(Matrix toValue, Duration duration)
{
To = toValue;
Duration = duration;
}
public MatrixAnimation(Matrix toValue, Duration duration, FillBehavior fillBehavior)
{
To = toValue;
Duration = duration;
FillBehavior = fillBehavior;
}
public MatrixAnimation(Matrix fromValue, Matrix toValue, Duration duration)
{
From = fromValue;
To = toValue;
Duration = duration;
}
public MatrixAnimation(Matrix fromValue, Matrix toValue, Duration duration, FillBehavior fillBehavior)
{
From = fromValue;
To = toValue;
Duration = duration;
FillBehavior = fillBehavior;
}
protected override Freezable CreateInstanceCore()
{
return new MatrixAnimation();
}
protected override Matrix GetCurrentValueCore(Matrix defaultOriginValue, Matrix defaultDestinationValue, AnimationClock animationClock)
{
if (animationClock.CurrentProgress == null)
{
return Matrix.Identity;
}
var normalizedTime = animationClock.CurrentProgress.Value;
if (EasingFunction != null)
{
normalizedTime = EasingFunction.Ease(normalizedTime);
}
var from = From ?? defaultOriginValue;
var to = To ?? defaultDestinationValue;
var newMatrix = new Matrix(
((to.M11 - from.M11) * normalizedTime) + from.M11,
((to.M12 - from.M12) * normalizedTime) + from.M12,
((to.M21 - from.M21) * normalizedTime) + from.M21,
((to.M22 - from.M22) * normalizedTime) + from.M22,
((to.OffsetX - from.OffsetX) * normalizedTime) + from.OffsetX,
((to.OffsetY - from.OffsetY) * normalizedTime) + from.OffsetY);
return newMatrix;
}
}
后面代码的示例用法:
protected void AnimateMatrix(MatrixTransform matrixTransform, Matrix toMatrix, TimeSpan duration)
{
if (matrixTransform is MatrixTransform mt && toMatrix is Matrix to && duration is TimeSpan ts)
AnimateMatrix(mt, mt.Matrix, to, duration);
}
protected void AnimateMatrix(MatrixTransform matrixTransform, Matrix? fromMatrix, Matrix? toMatrix, TimeSpan duration)
{
if (matrixTransform is MatrixTransform mt)
mt.BeginAnimation(MatrixTransform.MatrixProperty, GetMatrixAnimation(fromMatrix, toMatrix, duration));
}
private MatrixAnimation GetMatrixAnimation(Matrix? fromMatrix, Matrix? toMatrix, TimeSpan duration)
{
return new MatrixAnimation(fromMatrix ?? Matrix.Identity, toMatrix ?? Matrix.Identity, new Duration(duration));
}