WFP:Geometries几何图形集合--Geometry几何图形(1)

Geometry几何图形集合+3D变换

实现效果:

  1. 展示玻璃效果的Radiobutton
  2. 选择页面时页面的出现及退出呈现动画旋转、缩放效果

clipboard.png
有关具体类的含义见下章解析。
文件结构:

clipboard.png

主窗口xaml:
主窗口DockPanel承载左侧玻璃Radiobutton按钮区域Border及右侧屏幕的区域Grid,Grid下加载黑色方格+径向渐变色的背景方框、加载页面Page的Frame的ScrollView区域、显示3D动画ViewBox的区域Border。

  1. Viewbox的长宽绑定ScrollView的实际长宽,其中的3D材质的VisualBrush的Visual源绑定到ScrollView元素,同时进行旋转、缩放动画。
  2. 当选择按钮时,在右侧Viewbox执行当前页面的退出动画3D效果。同时Checked事件设置新页面索引,执行完成退出动画后及,再执行新页面的进入动画3D效果。

Radiobutton代码:

<StackPanel VerticalAlignment="Stretch" Margin="10">
    <RadioButton x:Name="Example1RadioButton" Checked="SampleSelected" Margin="0,0,0,10">Geometry Usage</RadioButton>
    <RadioButton Checked="SampleSelected" Margin="0,0,0,10">Shape Geometries</RadioButton>
    <RadioButton Checked="SampleSelected" Margin="0,0,0,10">PathGeometry</RadioButton>
    <RadioButton Checked="SampleSelected" Margin="0,0,0,10">Geometry Attribute Syntax Example</RadioButton>
    <RadioButton Checked="SampleSelected">Combining Geometries Example</RadioButton>
  </StackPanel>

右侧展示页面动画及内容的xaml:
其中设有Frame的缩放对象ScaleTransform(取消无影响),

<Border Name="scrollViewerBorder">
    <ScrollViewer Name="myScrollViewer" Background="White"
      HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"
      HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
      <Frame Name="mainFrame" Background="White" ContentRendered="FrameContentRendered"
        NavigationUIVisibility="Hidden">
        <Frame.RenderTransform>
          <ScaleTransform />
        </Frame.RenderTransform>
      </Frame>
    </ScrollViewer>
  </Border>

3D动画容器代码:
内容装饰器ViewBox长宽绑定页面的容器ScrollView实际长宽,且其内容Viewport3D二维布局范围内包含的三维内容。

  1. 设置Viewport3D.Camera摄像机对象:PerspectiveCamera透视投影摄像机
  2. 设置Viewport3D.ModelVisual3D 3D模型视觉对象,其中包含3D模型环境光源对象AmbientLight
  3. 3D模型还包含使用指定的 Material 呈现 Geometry3D对象。

    1. 其GeometryModel3D.Geometry中包含三维三角基元类MeshGeometry3D 3D网状几何对象
    2. 其中GeometryModel3D.Material 3D素材对象设为光线漫射素材DiffuseMaterial ,其画刷DiffuseMaterial.Brush设置为VisualBrush,继承Visual的ScrollView对象作为画刷的Visual绑定源。
    3. 至此3D模型构建完成。
  4. ModelVisual3D.Transform 3D模型视觉对象的变换:

    1. RotateTransform3D.Rotation 3D旋转对象设置为AxisAngleRotation3D 3D绕轴角度旋转对象。
    2. 设置ScaleTransform3D缩放3D变换。
<Border>
    <Border ClipToBounds="True">
      <Viewbox 
        Stretch="Fill"
        Width="{Binding ElementName=myScrollViewer, Path=ActualWidth}"
        Height="{Binding ElementName=myScrollViewer, Path=ActualHeight}">
        <Viewport3D 
          Name="myViewport3D"
          Opacity="1" IsHitTestVisible="False">
          <Viewport3D.Camera>
            <PerspectiveCamera 
              LookDirection="0,0,-2" 
              UpDirection="0,1,0"  
              Position="0,0,5" 
              FieldOfView="90"/>
          </Viewport3D.Camera>
          <ModelVisual3D>

            <ModelVisual3D.Children>
              <ModelVisual3D>
                <ModelVisual3D.Content>
                  <AmbientLight Color="#FFFFFFFF" />
                </ModelVisual3D.Content>
              </ModelVisual3D>
              <ModelVisual3D>
                <ModelVisual3D.Children>
                  <ModelVisual3D>
                    <ModelVisual3D.Content>
                      <GeometryModel3D x:Name="myPlane">
                        <GeometryModel3D.Geometry>
                          <MeshGeometry3D 
                            x:Name="myGeometry"
                            TriangleIndices="0,1,2 3,4,5, 11,10,9,8,7,6"                           
                            TextureCoordinates="0,0 0,-1 -1,-1 -1,-1 -1,0 0,0   -1,-1 -1,0 0,0 0,0 0,-1 -1,-1  "
                            Positions="12,-9,0 12,9,0 -12,9,0 -12,9,0 -12,-9,0 12,-9,0" />
                        </GeometryModel3D.Geometry>
                        <GeometryModel3D.Material>
                          <DiffuseMaterial>
                            <DiffuseMaterial.Brush>
                              <VisualBrush 
                                RenderOptions.CacheInvalidationThresholdMinimum="0"
                                RenderOptions.CachingHint="Cache"
                                Visual="{Binding ElementName=myScrollViewer}" />
                            </DiffuseMaterial.Brush>
                          </DiffuseMaterial>
                        </GeometryModel3D.Material>
                      </GeometryModel3D>
                    </ModelVisual3D.Content>
                    <ModelVisual3D.Transform>
                      <Transform3DGroup>
                        <RotateTransform3D x:Name="myHorizontalRotation"
                          CenterX="0" CenterY="0" CenterZ="0">
                          <RotateTransform3D.Rotation>
                            <AxisAngleRotation3D Axis="0,1,0" Angle="0"
                             x:Name="MyHorizontalAxisAngleRotation3D" />
                          </RotateTransform3D.Rotation>
                        </RotateTransform3D>
                        <ScaleTransform3D x:Name="MyScaleTransform3D" 
                          ScaleX="1" ScaleY="1" ScaleZ="1" />
                      </Transform3DGroup>
                    </ModelVisual3D.Transform>
                  </ModelVisual3D>
                </ModelVisual3D.Children>
              </ModelVisual3D>
            </ModelVisual3D.Children>
          </ModelVisual3D>
        </Viewport3D>
      </Viewbox>
    </Border>
  </Border>

选定按钮后页面触发器执行退出3D动画:

  1. 对上面的3D模型的水平轴、缩放x/y/z的值进行动画
  2. 同理设置页面进入时的3D模型动画效果,作为动画资源,被设置为退出动画后Completed》完成进入动画的执行。
<Page.Triggers>
    <EventTrigger RoutedEvent="RadioButton.Checked">
      <BeginStoryboard>
        <Storyboard Completed="ZoomOutStoryboardCompleted">
          <DoubleAnimation Storyboard.TargetName="MyHorizontalAxisAngleRotation3D"
            Storyboard.TargetProperty="Angle"
            From="0" To="360" Duration="0:0:1"  AutoReverse="False" FillBehavior="Stop"
            BeginTime="0:0:1" AccelerationRatio="1"
            />
          <DoubleAnimation Storyboard.TargetName="MyScaleTransform3D"
            Storyboard.TargetProperty="ScaleX"
            From="1" To="0" Duration="0:0:2"  AutoReverse="False" AccelerationRatio="1"
            />
          <DoubleAnimation Storyboard.TargetName="MyScaleTransform3D"
            Storyboard.TargetProperty="ScaleY"
            From="1" To="0" Duration="0:0:2"  AutoReverse="False" AccelerationRatio="1"
            />
          <DoubleAnimation Storyboard.TargetName="MyScaleTransform3D"
            Storyboard.TargetProperty="ScaleZ"
            From="1" To="0.1" Duration="0:0:2"  AutoReverse="False" AccelerationRatio="1"
            />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Page.Triggers>

后台代码:
主页面初始化时就储存各页面初始化对象:
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;
}

当选定一个按钮后发生:

  1. 设置3D三角基元的开始位置
  2. scrollViewerBorder内容隐藏,只显示动画界面
  3. 设置选定的页面对应索引值,作为退场动画后加载新页面的索引值。
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;
    }
}

扩展:

  1. 以上按钮点击在某种情况下有bug:当正在显示第一个页面退场时点击第二个按钮,随机马上再点击之前的第一个页面按钮,那么当第一个页面退出动画完成后,不会出现第一个页面的进场动画及内容显示.
  2. 分析原因:同一个页面退场动画执行后,再次触发同样的动画时,会覆盖之前的效果。其中包括完成动画要执行的mainFrame.Navigate方法并没有执行。
  3. 当新的退出动画完成后发现mainFrame.Navigate导航的内容还是原来的第一个页面,那么就不会再重新程序内容及进场动画,此时页面内容是隐藏的。
  4. 临时解决方法:记录当前页面索引值,比较确定是否最后选择的页面还是之前第一个,那么直接显示内容画面。
private void ZoomOutStoryboardCompleted(object sender, EventArgs args)
{
    mainFrame.Navigate(_examples[_sampleIndex]);
   
    if (_currentIndex == _sampleIndex)
    {                
        scrollViewerBorder.Visibility = Visibility.Visible;
    }
    else
    {
        _currentIndex = _sampleIndex;
    }
}

玻璃按钮请看下一章。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值