Geometry几何图形集合+3D变换
实现效果:
- 展示玻璃效果的Radiobutton
- 选择页面时页面的出现及退出呈现动画旋转、缩放效果
主窗口xaml:
主窗口DockPanel承载左侧玻璃Radiobutton按钮区域Border及右侧屏幕的区域Grid,Grid下加载黑色方格+径向渐变色的背景方框、加载页面Page的Frame的ScrollView区域、显示3D动画ViewBox的区域Border。- Viewbox的长宽绑定ScrollView的实际长宽,其中的3D材质的VisualBrush的Visual源绑定到ScrollView元素,同时进行旋转、缩放动画。
- 当选择按钮时,在右侧Viewbox执行当前页面的退出动画3D效果。同时Checked事件设置新页面索引,执行完成退出动画后及,再执行新页面的进入动画3D效果。
Radiobutton代码:
Geometry Usage Shape Geometries PathGeometry Geometry Attribute Syntax Example Combining Geometries Example
右侧展示页面动画及内容的xaml:
其中设有Frame的缩放对象ScaleTransform(取消无影响),3D动画容器代码:
内容装饰器ViewBox长宽绑定页面的容器ScrollView实际长宽,且其内容Viewport3D二维布局范围内包含的三维内容。- 设置Viewport3D.Camera摄像机对象:PerspectiveCamera透视投影摄像机
- 设置Viewport3D.ModelVisual3D 3D模型视觉对象,其中包含3D模型环境光源对象AmbientLight
-
3D模型还包含使用指定的 Material 呈现 Geometry3D对象。
- 其GeometryModel3D.Geometry中包含三维三角基元类MeshGeometry3D 3D网状几何对象
- 其中GeometryModel3D.Material 3D素材对象设为光线漫射素材DiffuseMaterial ,其画刷DiffuseMaterial.Brush设置为VisualBrush,继承Visual的ScrollView对象作为画刷的Visual绑定源。
- 至此3D模型构建完成。
-
ModelVisual3D.Transform 3D模型视觉对象的变换:
- RotateTransform3D.Rotation 3D旋转对象设置为AxisAngleRotation3D 3D绕轴角度旋转对象。
- 设置ScaleTransform3D缩放3D变换。
选定按钮后页面触发器执行退出3D动画:
- 对上面的3D模型的水平轴、缩放x/y/z的值进行动画
- 同理设置页面进入时的3D模型动画效果,作为动画资源,被设置为退出动画后Completed》完成进入动画的执行。
后台代码:
主页面初始化时就储存各页面初始化对象:ps:可设置动态加载页面?public SampleViewer(){ InitializeComponent(); _examples = new Page[5]; _examples[0] = new GeometryUsageExample(); _examples[1] = new ShapeGeometriesExample(); _examples[2] = new PathGeometryExample(); _examples[3] = new CombiningGeometriesExample(); _examples[4] = new GeometryAttributeSyntaxExample();}
主页面加载后执行选定一个Radiobutton,同时触发执行之前画面的退场动画。
private void PageLoaded(object sender, RoutedEventArgs args){ Example1RadioButton.IsChecked = true;}
动画退场后执行Frame导航到新选定的页面并显示内容。
private void ZoomOutStoryboardCompleted(object sender, EventArgs args){ mainFrame.Navigate(_examples[_sampleIndex]);}
新页面加载呈现内容后执行进场动画资源启动:
private void FrameContentRendered(object sender, EventArgs args){ var s = (Storyboard)Resources["ZoomInStoryboard"]; s.Begin(this);}
进场动画完成后执行页面内容的显示,遮住动画画面并提供操作:
private void ZoomInStoryboardCompleted(object sender, EventArgs e){ scrollViewerBorder.Visibility = Visibility.Visible;}
当选定一个按钮后发生:
- 设置3D三角基元的开始位置
- scrollViewerBorder内容隐藏,只显示动画界面
- 设置选定的页面对应索引值,作为退场动画后加载新页面的索引值。
private void SampleSelected(object sender, RoutedEventArgs args){ var points = new Point3DCollection(); var ratio = myScrollViewer.ActualWidth/myScrollViewer.ActualHeight; points.Add(new Point3D(5, -5*ratio, 0)); points.Add(new Point3D(5, 5*ratio, 0)); points.Add(new Point3D(-5, 5*ratio, 0)); points.Add(new Point3D(-5, 5*ratio, 0)); points.Add(new Point3D(-5, -5*ratio, 0)); points.Add(new Point3D(5, -5*ratio, 0)); points.Add(new Point3D(-5, 5*ratio, 0)); points.Add(new Point3D(-5, -5*ratio, 0)); points.Add(new Point3D(5, -5*ratio, 0)); points.Add(new Point3D(5, -5*ratio, 0)); points.Add(new Point3D(5, 5*ratio, 0)); points.Add(new Point3D(-5, 5*ratio, 0)); myGeometry.Positions = points; myViewport3D.Width = 100; myViewport3D.Height = 100*ratio; scrollViewerBorder.Visibility = Visibility.Hidden; var button = sender as RadioButton; if (button != null) { if (button.Content.ToString() == "Geometry Usage") _sampleIndex = 0; else if (button.Content.ToString() == "Shape Geometries") _sampleIndex = 1; else if (button.Content.ToString() == "PathGeometry") _sampleIndex = 2; else if (button.Content.ToString() == "Combining Geometries Example") _sampleIndex = 3; else if (button.Content.ToString() == "Geometry Attribute Syntax Example") _sampleIndex = 4; }}
扩展:
- 以上按钮点击在某种情况下有bug:当正在显示第一个页面退场时点击第二个按钮,随机马上再点击之前的第一个页面按钮,那么当第一个页面退出动画完成后,不会出现第一个页面的进场动画及内容显示.
- 分析原因:同一个页面退场动画执行后,再次触发同样的动画时,会覆盖之前的效果。其中包括完成动画要执行的mainFrame.Navigate方法并没有执行。
- 当新的退出动画完成后发现mainFrame.Navigate导航的内容还是原来的第一个页面,那么就不会再重新程序内容及进场动画,此时页面内容是隐藏的。
- 临时解决方法:记录当前页面索引值,比较确定是否最后选择的页面还是之前第一个,那么直接显示内容画面。
private void ZoomOutStoryboardCompleted(object sender, EventArgs args){ mainFrame.Navigate(_examples[_sampleIndex]); if (_currentIndex == _sampleIndex) { scrollViewerBorder.Visibility = Visibility.Visible; } else { _currentIndex = _sampleIndex; }}
玻璃按钮请看下一章。