1. 程式人生 > >WPF3D立方體圖形展開動畫思路

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

# WPF3D立方體圖形展開動畫 **效果圖:** ![](https://img2020.cnblogs.com/blog/1019257/202103/1019257-20210330111642498-605802544.gif) ##### 規定: 立方體中心為(000),稜長為2,則(111)(-1-1-1)等1,-1三維組合的八個點為其頂點 **座標系:** ![](https://img2020.cnblogs.com/blog/1019257/202103/1019257-20210330111658193-151828452.png) **補充:** WPF 3D 分為**中心對稱旋轉**([RotateTransform3D](https://docs.microsoft.com/en-us/dotnet/api/system.windows.media.media3d.rotatetransform3d)),**平移旋轉**([TranslateTransform3D](https://docs.microsoft.com/en-us/dotnet/api/system.windows.media.media3d.translatetransform3d))和**比例縮減**([ScaleTransform3D](https://docs.microsoft.com/en-us/dotnet/api/system.windows.media.media3d.scaletransform3d)),立體圖形展開目前只用到**對稱和平移變換** ## 1 按軸旋轉的面 ![](https://img2020.cnblogs.com/blog/1019257/202103/1019257-20210330111711276-740245118.gif) 如圖所示,則其是按照由(-1-1-1)到(1-1-1)的軸運動 換算成中心對稱,也就是這條邊的中點,則對稱點為(0,-1,-1) ***此動畫可描述為,對點(0,-1,-1)做中心對稱變換,沿X軸旋轉90度。*** Code: ```c# //設定對稱中心 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度。*** ![](https://img2020.cnblogs.com/blog/1019257/202103/1019257-20210330111728755-1875719852.gif) Code: ```c# 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 連線按軸旋轉的面的面 即二級旋轉面 ![](https://img2020.cnblogs.com/blog/1019257/202103/1019257-20210330111740149-279976121.gif) 此時,我們可以把它理解為兩個旋轉的結合,**一個軸對稱旋轉+一個平移旋轉** ###### 1 軸對稱旋轉: ![](https://img2020.cnblogs.com/blog/1019257/202103/1019257-20210330111748141-1937387730.gif) 描述為,對點(11-1)進行旋轉,沿Z軸旋轉180度。 Code: ```c# 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 平移旋轉: ![](https://img2020.cnblogs.com/blog/1019257/202103/1019257-20210330111757246-571280012.gif) 從側面看的平移軌跡: ![](https://img2020.cnblogs.com/blog/1019257/202103/1019257-20210330111816282-2022094923.png) 此平移按X和Y軸方向分解示意圖: ![](https://img2020.cnblogs.com/blog/1019257/202103/1019257-20210330111823913-917389236.png) 其中X方向可以描述為: 在t時間內,L為邊長 x方向值為:x=L*Sin(a) y方向值為:y=L*Cos(a) 其中角度a可描述為:(PI/2)*currentTime/totalAnimationDuration 如果我們將動畫描述成幀動畫,綜上: X方向平移動畫幀 ```c# LinearDoubleKeyFrame GetFace4OffsetXKeyFrame(double time) { return new LinearDoubleKeyFrame(borderLength * Math.Sin(time * (Math.PI / 2) / keyFrameAnimationTotalTimeM), KeyTime.FromTimeSpan(TimeSpan.FromSeconds(time))); } ``` Y方向平移動畫幀 ```c# LinearDoubleKeyFrame GetFace4OffsetYKeyFrame(double time) { return new LinearDoubleKeyFrame(-(borderLength - borderLength * Math.Cos(time * (Math.PI / 2) / keyFrameAnimationTotalTimeM)), KeyTime.FromTimeSpan(TimeSpan.FromSeconds(time))); } ``` ## 3 三級旋轉面 ![](https://img2020.cnblogs.com/blog/1019257/202103/1019257-20210330111836646-2018350229.gif) 同理,我們可以把它理解為兩個旋轉的結合,**一個軸對稱旋轉+一個平移旋轉** ###### 軸對稱旋轉: ![](https://img2020.cnblogs.com/blog/1019257/202103/1019257-20210330111842482-1134447068.gif) 描述為,對點(-110)進行旋轉,沿Z軸旋轉270度。 Code: ```c# 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·軌跡旋轉 ![](https://img2020.cnblogs.com/blog/1019257/202103/1019257-20210330112134948-1384620469.png) ###### 則沿著B軸的旋轉,與二級面分解一樣: ![](https://img2020.cnblogs.com/blog/1019257/202103/1019257-20210330111901068-2037259848.png) ###### A軸旋轉分解: 對於y,y=Sin(a2) 對於x,分為**兩種情況**: 當a2處於0-PI/2時,x=Cos(a2), 當a2處於PI/2-PI時,y=L-Cos(a2) ![](https://img2020.cnblogs.com/blog/1019257/202103/1019257-20210330111907843-580179068.png) 把上述兩個分解加一起就得到了X=xa+xb,y=ya+yb, Code: X ```c# 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 ```c# 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 雙重軸對稱旋轉+平移旋轉面 ![](https://img2020.cnblogs.com/blog/1019257/202103/1019257-20210330111919114-2083910213.gif) 如圖所示,左邊這個橙色的面,在黑色的三級旋轉面之上又增加一個沿著Z軸的旋轉。 此時可以簡單地分解為**三級旋轉面的旋轉+沿著Z軸的旋轉**。 ![](https://img2020.cnblogs.com/blog/1019257/202103/1019257-20210330111925919-1658700087.gif) ###### 三級旋轉面的旋轉: 見上文 ###### 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