代码之家  ›  专栏  ›  技术社区  ›  Homde

使用MatrixtTransform平滑动画?

  •  2
  • Homde  · 技术社区  · 16 年前

    我正在尝试做一个矩阵动画,在这个动画中,我同时缩放和变换画布。我发现的唯一方法是使用矩阵变换和矩阵动画。由于内置矩阵似乎没有任何插值(仅用于路径/旋转),因此似乎唯一的选择是尝试构建插值和离散矩阵关键帧的自己。

    我做了一个基本的实现,但它并不完全顺利,我不确定这是否是最好的方法,以及如何处理帧速率等。有人有改进的建议吗?代码如下:

            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;
    
        }
    
    5 回复  |  直到 12 年前
        1
  •  3
  •   LukeN    15 年前

    试试这个!只要你不旋转/剪切,它就会起作用。

    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); }
            }
        }
    }
    
        2
  •  1
  •   Thorsten S.    16 年前

    好吧,如果你在msdn上问的话

    http://msdn.microsoft.com/en-us/library/system.windows.media.animation.discretematrixkeyframe.aspx

    你得到的答案是离散矩阵关键帧 突然改变,你应该使用线性双关键帧 或SplineDoubleKeyFrame与 源代码 !

    编辑:啊,我明白了,矩阵变换只支持离散的 转换,所以实际上你有跳跃的问题。 所以我建议使用矩形框架

    // 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
                    );
    

    只需使用线性或splinerectkeyframe,设置持续时间/按键时间和 需要。要获得比例,您需要计算并设置末端宽度/高度,但这不应该是问题。

        3
  •  1
  •   pwlodek    15 年前

    我已经实现了MatrixAnimation类,它支持平滑的翻译、缩放和旋转动画。它还支持放松功能!找到它 here

        4
  •  1
  •   bor    12 年前

    我喜欢鲁肯的回答。适用于简单的翻译/缩放动画。
    我在这段代码中添加了宽松(手工制作,而不是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)

        5
  •  0
  •   Brad Werth    12 年前

    我能想到的一种方法是将矩阵转换为 TransformGroup 其中包含 ScaleTransform , RotateTransform 和A TranslateTransform ,然后使用普通动画设置这些动画,然后在动画完成后,根据每个变换中的值重新创建矩阵?