一个使用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就可实现相同的功能并能优化了性能