WPF3D立方體圖形展開動畫思路

猝不及防發表於2021-03-30

WPF3D立方體圖形展開動畫

效果圖:

規定:

立方體中心為(000),稜長為2,則(111)(-1-1-1)等1,-1三維組合的八個點為其頂點

座標系:

補充:

WPF 3D 分為中心對稱旋轉RotateTransform3D),平移旋轉TranslateTransform3D)和比例縮減ScaleTransform3D),立體圖形展開目前只用到對稱和平移變換

1 按軸旋轉的面

如圖所示,則其是按照由(-1-1-1)到(1-1-1)的軸運動

換算成中心對稱,也就是這條邊的中點,則對稱點為(0,-1,-1)

此動畫可描述為,對點(0,-1,-1)做中心對稱變換,沿X軸旋轉90度。

Code:

			//設定對稱中心
	    face0RotateTransform3D.CenterX = 0;
            face0RotateTransform3D.CenterY = -1;
            face0RotateTransform3D.CenterZ = -1;
			//設定旋轉角度
            (face0RotateTransform3D.Rotation as AxisAngleRotation3D).Axis = new Vector3D(1, 0, 0);
            DoubleAnimation face0AxisAngleRotation3DAnimation = new DoubleAnimation();
            face0AxisAngleRotation3DAnimation.From = 0;
            face0AxisAngleRotation3DAnimation.To = -90;
            face0AxisAngleRotation3DAnimation.Duration = new Duration(TimeSpan.FromSeconds(keyFrameAnimationTotalTimeM));

同理可得另一個面:對點(1,-1,-1)做中心對稱變換,沿Z軸旋轉90度。

Code:

 	    face3RotateTransform3D.CenterX = 1;
            face3RotateTransform3D.CenterY = -1;
            face3RotateTransform3D.CenterZ = -1;
            (face3RotateTransform3D.Rotation as AxisAngleRotation3D).Axis = new Vector3D(0, 0, 1);
            DoubleAnimation DoubleAnimation = new DoubleAnimation();
            DoubleAnimation.From = 0;
            DoubleAnimation.To = -90;

2 連線按軸旋轉的面的面

即二級旋轉面

此時,我們可以把它理解為兩個旋轉的結合,一個軸對稱旋轉+一個平移旋轉

1 軸對稱旋轉:

描述為,對點(11-1)進行旋轉,沿Z軸旋轉180度。

Code:

            face4RotateTransform3D.CenterX = 1;
            face4RotateTransform3D.CenterY = 1;
            face4RotateTransform3D.CenterZ = -1;
            (face4RotateTransform3D.Rotation as AxisAngleRotation3D).Axis = new Vector3D(0, 0, 1);
            DoubleAnimation DoubleAnimation = new DoubleAnimation();
            DoubleAnimation.From = 0;
            DoubleAnimation.To = -180;
2 平移旋轉:

從側面看的平移軌跡:

此平移按X和Y軸方向分解示意圖:

其中X方向可以描述為:

在t時間內,L為邊長

x方向值為:x=L*Sin(a)

y方向值為:y=L*Cos(a)

其中角度a可描述為:(PI/2)*currentTime/totalAnimationDuration

如果我們將動畫描述成幀動畫,綜上:

X方向平移動畫幀

 LinearDoubleKeyFrame GetFace4OffsetXKeyFrame(double time)
        {
            return new LinearDoubleKeyFrame(borderLength * Math.Sin(time * (Math.PI / 2) / keyFrameAnimationTotalTimeM), KeyTime.FromTimeSpan(TimeSpan.FromSeconds(time)));
        }

Y方向平移動畫幀

  LinearDoubleKeyFrame GetFace4OffsetYKeyFrame(double time)
        {
            return new LinearDoubleKeyFrame(-(borderLength - borderLength * Math.Cos(time * (Math.PI / 2) / keyFrameAnimationTotalTimeM)), KeyTime.FromTimeSpan(TimeSpan.FromSeconds(time)));
        }

3 三級旋轉面

同理,我們可以把它理解為兩個旋轉的結合,一個軸對稱旋轉+一個平移旋轉

軸對稱旋轉:

描述為,對點(-110)進行旋轉,沿Z軸旋轉270度。

Code:

            face1RotateTransform3D.CenterX = -1;
            face1RotateTransform3D.CenterY = 1;
            face1RotateTransform3D.CenterZ = 0;
            (face1RotateTransform3D.Rotation as AxisAngleRotation3D).Axis = new Vector3D(0, 0, 1);
            DoubleAnimation DoubleAnimation = new DoubleAnimation();
            DoubleAnimation.From = 0;
            DoubleAnimation.To = -270;
            DoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(keyFrameAnimationTotalTimeM));
平移旋轉:

平移旋轉的量需要通過分解軸旋轉來得出。

通過觀察我們可以將其分為兩個軸旋轉,第一個旋轉是該面沿著A軸的軸對稱旋轉(自身旋轉),第二個是二級面的沿著B軸的軸對稱旋轉(相對面旋轉)

A稜邊沿著A·軌跡旋轉,B稜邊沿著B·軌跡旋轉

則沿著B軸的旋轉,與二級面分解一樣:

A軸旋轉分解:

對於y,y=Sin(a2)

對於x,分為兩種情況

當a2處於0-PI/2時,x=Cos(a2),

當a2處於PI/2-PI時,y=L-Cos(a2)

把上述兩個分解加一起就得到了X=xa+xb,y=ya+yb,

Code:

X

 LinearDoubleKeyFrame GetFace1OffsetXKeyFrame(double time)
        {
            //自身邊的定位座標
            double angle = time / keyFrameAnimationTotalTimeM;
            double xa, xb;
            double xTotal;
            if (angle <= 1 / 2)
            {
                //0-1/2PI
                xa = borderLength * Math.Cos(Math.PI * time / keyFrameAnimationTotalTimeM);
            }
            else
            {
                //1/2PI-PI
                xa = borderLength - borderLength * Math.Cos(Math.PI * time / keyFrameAnimationTotalTimeM);
            }
            //前軸定位座標
            xb = borderLength * Math.Sin((Math.PI / 2) * time / keyFrameAnimationTotalTimeM);
            xTotal = xa + xb;
            return new LinearDoubleKeyFrame(xTotal, KeyTime.FromTimeSpan(TimeSpan.FromSeconds(time)));
        }

Y

 Timeline Face1ExpandedAnimation_MoveOffsetY_UsingKeyFrames()
        {
            DoubleAnimationUsingKeyFrames DoubleAnimation = new DoubleAnimationUsingKeyFrames();
            DoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(keyFrameAnimationTotalTimeM));
            DoubleAnimation.Completed += ((sender, e) =>
            {
                faceStoryboard.Remove(tileButton);
            });
            Storyboard.SetTargetName(DoubleAnimation, "face1TranslateTransform3D");
            Storyboard.SetTargetProperty(DoubleAnimation,
                new PropertyPath(TranslateTransform3D.OffsetYProperty));

            for (double i = 0; i <= keyFrameAnimationTotalTimeM + keyFrameAnimationIntervalM; i += keyFrameAnimationIntervalM)
            {
                DoubleAnimation.KeyFrames.Add(GetFace1OffsetYKeyFrame(i));
            }
            return DoubleAnimation;
        }C

4 雙重軸對稱旋轉+平移旋轉面

如圖所示,左邊這個橙色的面,在黑色的三級旋轉面之上又增加一個沿著Z軸的旋轉。

此時可以簡單地分解為三級旋轉面的旋轉+沿著Z軸的旋轉

三級旋轉面的旋轉:

見上文

Z軸旋轉

可描述為:對點(-1-11)進行旋轉,沿Z軸旋轉90度。

            face5RotateTransform3D.CenterX = -1;
            face5RotateTransform3D.CenterY = -1;
            face5RotateTransform3D.CenterZ = 1;
            (face5RotateTransform3D.Rotation as AxisAngleRotation3D).Axis = new Vector3D(0, 1, 0);
            DoubleAnimation DoubleAnimation = new DoubleAnimation();
            DoubleAnimation.From = 0;
            DoubleAnimation.To = -90;
            DoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(keyFrameAnimationTotalTimeM));

相關文章