一个使用Wpf模拟Windows7 Win+Tab页面切换的小程序,使用快捷键Ctrl+Down或Ctrl+Up在示例程序各个页面元素之间滑动导航,在本例中,使用Viewport2DVisual3D宿主二维控件,在这里为方便示例,二维控件仅简单的使用了一个Image,以下是界面缩略图,有兴趣的朋友可以下载源码
在建立本示例中的三维场景时,使用了Viewport3D,PerspectiveCamera,AmbientLight,Viewport2DVisual3D,RotateTransform3D,TranslateTransform3D,ScaleTransform3D等元素,下面分别简单说明一下这些元素在三维场景中分别充当了什么角色
1.Viewport3D :Viewport3D是一个2D可视化元素,它是在2D场景中封装3D元素的容器控件,具有两个重要的属性
public Visual3DCollection Children { get ; }
Camera 为3D场景指定观察者所处的位置
Children 表示Viewport3D的所有3D子控件的集合类
2.PerspectiveCamera 表示透视投影摄像机,在本示例中使用它对3D场景进行透视投影
3.AmbientLight 灯光用来照亮3D场景
4.Viewport2DVisual3D 在3D场景中呈现可交互的2D控件,在本示例中就使用了6个Viewport2DVisual3D元素分别呈现了六幅Image
5.RotateTransform3D 对3D元素应用旋转,本示例中使用它对Viewport2DVisual3D进行Y轴45度旋转的模型变换
6.TranslateTransform3D 对3D元素应用平移,本示例中使用它对Viewport2DVisual3D分别进行X,Y,Z平移的模型变换
7.ScaleTransform3D 对3D元素应用拉伸缩放,本示例中使用它对Viewport2DVisual3D进行了X,Y的拉伸模型变换
以下为定义3D场景的XAML代码
2 < Viewport3D.Camera >
3 < PerspectiveCamera Position ="0,0,8" />
4 </ Viewport3D.Camera >
5 < Viewport2DVisual3D x:Name ="viewport2DVisual3D0" Geometry =" {StaticResource geometry} "
6 < Viewport2DVisual3D.Transform >
7 < Transform3DGroup >
8 < RotateTransform3D CenterX ="0" CenterY ="0" CenterZ ="0" >
9 < RotateTransform3D.Rotation >
10 < AxisAngleRotation3D Axis ="0,1,0" Angle ="35" />
11 </ RotateTransform3D.Rotation >
12 </ RotateTransform3D >
13 < TranslateTransform3D OffsetX ="0" OffsetY ="0" OffsetZ ="0" />
14 < ScaleTransform3D CenterX ="0" CenterY ="0"
15 </ Transform3DGroup >
16 </ Viewport2DVisual3D.Transform >
17 < Viewport2DVisual3D.Visual >
18 < Image Source ="Images\051027nature01.jpg" Stretch ="Fill"
19 </ Viewport2DVisual3D.Visual >
20 </ Viewport2DVisual3D >
21 < Viewport2DVisual3D x:Name ="viewport2DVisual3D1" Geometry =" {StaticResource geometry} "
22 < Viewport2DVisual3D.Transform >
23 < Transform3DGroup >
24 < RotateTransform3D CenterX ="0" CenterY ="0" CenterZ ="0" >
25 < RotateTransform3D.Rotation >
26 < AxisAngleRotation3D Axis ="0,1,0" Angle ="35" />
27 </ RotateTransform3D.Rotation >
28 </ RotateTransform3D >
29 < TranslateTransform3D OffsetX ="-1" OffsetY ="1" OffsetZ ="-4" />
30 < ScaleTransform3D CenterX ="0" CenterY ="0" CenterZ ="0"
31 </ Transform3DGroup >
32 </ Viewport2DVisual3D.Transform >
33 < Viewport2DVisual3D.Visual >
34 < Image Source ="Images\051027nature02.jpg" Stretch ="Fill"
35 </ Viewport2DVisual3D.Visual >
36 </ Viewport2DVisual3D >
37 < Viewport2DVisual3D x:Name ="viewport2DVisual3D2" Geometry =" {StaticResource geometry} "
38 < Viewport2DVisual3D.Transform >
39 < Transform3DGroup >
40 < RotateTransform3D CenterX ="0" CenterY ="0" CenterZ ="0" >
41 < RotateTransform3D.Rotation >
42 < AxisAngleRotation3D Axis ="0,1,0" Angle ="35" />
43 </ RotateTransform3D.Rotation >
44 </ RotateTransform3D >
45 < TranslateTransform3D OffsetX ="-2" OffsetY ="1.5" OffsetZ ="-8" />
46 < ScaleTransform3D CenterX ="0" CenterY ="0" CenterZ ="0"
47 </ Transform3DGroup >
48 </ Viewport2DVisual3D.Transform >
49 < Viewport2DVisual3D.Visual >
50 < Image Source ="Images\11550549.jpg" Stretch ="Fill"
51 </ Viewport2DVisual3D.Visual >
52 </ Viewport2DVisual3D >
53 < Viewport2DVisual3D x:Name ="viewport2DVisual3D3" Geometry =" {StaticResource geometry} "
54 < Viewport2DVisual3D.Transform >
55 < Transform3DGroup >
56 < RotateTransform3D CenterX ="0" CenterY ="0" CenterZ ="0" >
57 < RotateTransform3D.Rotation >
58 < AxisAngleRotation3D Axis ="0,1,0" Angle ="35" />
59 </ RotateTransform3D.Rotation >
60 </ RotateTransform3D >
61 < TranslateTransform3D OffsetX ="-3" OffsetY ="1.5" OffsetZ ="-12" />
62 < ScaleTransform3D CenterX ="0" CenterY ="0" CenterZ ="0"
63 </ Transform3DGroup >
64 </ Viewport2DVisual3D.Transform >
65 < Viewport2DVisual3D.Visual >
66 < Image Source ="Images\11550556.jpg" Stretch ="Fill"
67 </ Viewport2DVisual3D.Visual >
68 </ Viewport2DVisual3D >
69 < Viewport2DVisual3D x:Name ="viewport2DVisual3D4" Geometry =" {StaticResource geometry} "
70 < Viewport2DVisual3D.Transform >
71 < Transform3DGroup >
72 < RotateTransform3D CenterX ="0" CenterY ="0" CenterZ ="0" >
73 < RotateTransform3D.Rotation >
74 < AxisAngleRotation3D Axis ="0,1,0" Angle ="35" />
75 </ RotateTransform3D.Rotation >
76 </ RotateTransform3D >
77 < TranslateTransform3D OffsetX ="-4" OffsetY ="1.5" OffsetZ ="-16" />
78 < ScaleTransform3D CenterX ="0" CenterY ="0" CenterZ ="0"
79 </ Transform3DGroup >
80 </ Viewport2DVisual3D.Transform >
81 < Viewport2DVisual3D.Visual >
82 < Image Source ="Images\11550560.jpg" Stretch ="Fill"
83 </ Viewport2DVisual3D.Visual >
84 </ Viewport2DVisual3D >
85 < Viewport2DVisual3D x:Name ="viewport2DVisual3D5" Geometry =" {StaticResource geometry} "
86 < Viewport2DVisual3D.Transform >
87 < Transform3DGroup >
88 < RotateTransform3D CenterX ="0" CenterY ="0" CenterZ ="0" >
89 < RotateTransform3D.Rotation >
90 < AxisAngleRotation3D Axis ="0,1,0" Angle ="35" />
91 </ RotateTransform3D.Rotation >
92 </ RotateTransform3D >
93 < TranslateTransform3D OffsetX ="-5" OffsetY ="1.5" OffsetZ ="-20" />
94 < ScaleTransform3D CenterX ="0" CenterY ="0" CenterZ ="0"
95 </ Transform3DGroup >
96 </ Viewport2DVisual3D.Transform >
97 < Viewport2DVisual3D.Visual >
98 < Image Source ="Images\051123Webshots05.jpg" Stretch ="Fill"
99 </ Viewport2DVisual3D.Visual >
100 </ Viewport2DVisual3D >
101 < ModelVisual3D >
102 < ModelVisual3D.Content >
103 < AmbientLight Color ="White" />
104 </ ModelVisual3D.Content >
105 </ ModelVisual3D >
106 </ Viewport3D >
通过以上的XAML语言定义了一个静态的3D场景,以下的代码实现将此3D场景支持动画效果,即模仿Windows7的Win+Tab切换特效
2 {
3 // 向前移动,取Viewport3D的第一个Viewport2DVisual3为当前Viewport2DVisual3D
4 var current = this .Viewport3D.Children[ 0 ];
5 var child1 = this .Viewport3D.Children[ 1 ];
6 var child2 = this .Viewport3D.Children[ 2 ];
7 var child3 = this .Viewport3D.Children[ 3 ];
8 var child4 = this .Viewport3D.Children[ 4 ];
9 var child5 = this .Viewport3D.Children[ 5 ];
10
11
12 this .Viewport3D.Children.RemoveAt( 0 );
13 this .Viewport3D.Children.Insert( 5 , current);
14
15 var translate = (current.Transform as Transform3DGroup).Children[ 1 ]
16
17 // 对每个Viewport2DVisual3D元素应用平移动画
18 AnimationVisualElement((current as Viewport2DVisual3D).Visual
19 AnimationVisualElement(translate, true , - 5.0 , 1.5 , - 20.0 );
20
21 translate = (child1.Transform as Transform3DGroup).Children[ 1 ]
22 AnimationVisualElement(translate, true , . 0 , . 0 , . 0 );
23
24 translate = (child2.Transform as Transform3DGroup).Children[ 1 ]
25 AnimationVisualElement(translate, true , - 1.0 , 1.0 , - 4.0 );
26
27 translate = (child3.Transform as Transform3DGroup).Children[ 1 ]
28 AnimationVisualElement(translate, true , - 2.0 , 1.5 , - 8.0 );
29
30 translate = (child4.Transform as Transform3DGroup).Children[ 1 ]
31 AnimationVisualElement(translate, true , - 3.0 , 1.5 , - 12.0 );
32
33 translate = (child5.Transform as Transform3DGroup).Children[ 1 ]
34 AnimationVisualElement(translate, true , - 4.0 , 1.5 , - 16.0 );
35
36 }
37
38 public void MoveCurrentToPrevious()
39 {
40 // 向后移动,取Viewport3D的最后一个Viewport2DVisual3D当前Viewport2DVisual3D
41 var current = this .Viewport3D.Children[ 5 ];
42 var child1 = this .Viewport3D.Children[ 0 ];
43 var child2 = this .Viewport3D.Children[ 1 ];
44 var child3 = this .Viewport3D.Children[ 2 ];
45 var child4 = this .Viewport3D.Children[ 3 ];
46 var child5 = this .Viewport3D.Children[ 4 ];
47
48 this .Viewport3D.Children.RemoveAt( 5 );
49 this .Viewport3D.Children.Insert( 0 , current);
50
51 var translate = (current.Transform as Transform3DGroup).Children[ 1 ]
52
53 AnimationVisualElement(translate, false , 0.0 , 0.0 , 0.0 );
55
56 translate = (child1.Transform as Transform3DGroup).Children[ 1 ]
57 AnimationVisualElement(translate, false , - 1.0 , 1.0 , - 4.0 );
58
59 translate = (child2.Transform as Transform3DGroup).Children[ 1 ]
60 AnimationVisualElement(translate, false , - 2.0 , 1.5 , - 8.0 );
61
62 translate = (child3.Transform as Transform3DGroup).Children[ 1 ]
63 AnimationVisualElement(translate, false , - 3.0 , 1.5 , - 12.0 );
64
65 translate = (child4.Transform as Transform3DGroup).Children[ 1 ]
66 AnimationVisualElement(translate, false , - 4.0 , 1.5 , - 16.0 );
67
68 translate = (child5.Transform as Transform3DGroup).Children[ 1 ]
69 AnimationVisualElement(translate, false , - 5.0 , 1.5 , - 20.0 );
70 }
71 private void AnimationVisualElement(FrameworkElement element, double duration)
72 {
73 if (element == null )
74 return ;
75 // 对Visual元素的Visibility应用动画
76 ObjectAnimationUsingKeyFrames objectAnimation = new ObjectAnimationUsingKeyFrames();
77 objectAnimation.KeyFrames.Add(
78 objectAnimation.KeyFrames.Add(
79 objectAnimation.Duration = TimeSpan.FromSeconds(duration);
80 objectAnimation.FillBehavior = FillBehavior.Stop;
81 element.BeginAnimation(FrameworkElement.VisibilityProperty, objectAnimation);
82
83 }
84 private void AnimationVisualElement(TranslateTransform3D translate, bool forward,
85 {
86 Duration duration = new Duration(TimeSpan.FromSeconds(. 4 ));
87 // 对TranslateTransform3D的X偏移量应用动画
88 DoubleAnimation animationX = new DoubleAnimation();
89 animationX.To = targetX;
90 animationX.Duration = duration;
91 animationX.AccelerationRatio = forward ? 0 : 1 ;
92 animationX.DecelerationRatio = forward ? 1 : 0 ;
93 translate.BeginAnimation(TranslateTransform3D.OffsetXProperty, animationX);
94 // 对TranslateTransform3D的Y偏移量应用动画
95 DoubleAnimation animationY = new DoubleAnimation();
96 animationX.To = targetY;
97 animationX.AccelerationRatio = forward ? 0.7 : 0.3 ;
98 animationX.DecelerationRatio = forward ? 0.3 : 0.7 ;
99 animationX.Duration = duration;
100 translate.BeginAnimation(TranslateTransform3D.OffsetYProperty, animationX);
101 // 对TranslateTransform3D的Z偏移量应用动画
102 DoubleAnimation animationZ = new DoubleAnimation();
103 animationZ.To = targetZ;
104 animationZ.AccelerationRatio = forward ? 0.3 : 0.7 ;
105 animationZ.DecelerationRatio = forward ? 0.7 : 0.3 ;
106 animationZ.Duration = duration;
107 translate.BeginAnimation(TranslateTransform3D.OffsetZProperty, animationZ);
108 }
在以上代码中主要实现了对ViewPort3D的6个子Viewport2DVisual3D分别应用TranslateTransform3D的平移动画,TranslateTransform3D具有三个跟位置有关的属性,分别表示X轴偏移量OffsetX,Y轴偏移量OffsetY,以及Z轴偏移量OffsetZ
由于OffsetX,OffsetY,OffsetY在TranslateTransform3D中被定义为Double类型的依赖项属性,因此可以使用DoubleAnimation对属性的目标值定义动画效果,最后通过TranslateTransform3D的BeginAnimation方法分别对OffsetX,OffsetY,OffsetY属性应用动画
最后定义快捷键事件,按下Ctrl+Down组合键,图片向前滑动,按下Ctrl+Up组合键,图片向后滑动
2 {
3 if (e.KeyStates == Keyboard.GetKeyStates(Key.Down) &&
4 Keyboard.Modifiers == ModifierKeys.Control)
5 {
6 // 向前移动Visual元素
7 this .MoveCurrentToNext();
8 }
9 else if (e.KeyStates == Keyboard.GetKeyStates(Key.Up) &&
10 Keyboard.Modifiers == ModifierKeys.Control)
11 {
12 // 向后移动Visual元素
13 this .MoveCurrentToPrevious();
14 }
15 else if (e.KeyStates == Keyboard.GetKeyStates(Key.Escape))
16 {
17 // 注销
18 Application.Current.Shutdown();
19 }
20 }
注:在本示例中连续使用了6个Viewport2DVisual3D三维元素,并且在每个Viewport2DVisual3D元素的Visual上宿主一个二维的Image控件,对于本示例,为优化性能,应尽可能的减少Viewport2DVisual3D的数目,在这里一个好的方法是使用三维元素ModelVisual3D来代替Viewport2DVisual3D,将六幅图片分别定义成Material,再将Material应用到六个对应的GeometryModel3D三维模型中,最后使用Model3DGroup将六个GeometryModel3D三维模型打包作为ModelVisual3D的Content属性值,因此只需要一个ModelVisual3D就可实现相同的功能并能优化了性能