你的位置:首页 > ASP.net教程

[ASP.net教程]WPF Viewport3D 解决透视模式时窗体模糊


最近折腾Viewport3D玩,遇到了一些诡异的问题,研究一下略有心得,特此和大家分享~

三维图形概述:

https://msdn.microsoft.com/zh-cn/library/ms747437.aspx

概要

三维坐标系

 
       二维图形的 WPF 坐标系将原点定位在呈现区域(通常是屏幕)的左上角。 在二维系统中,x 轴上的正值朝右,y 轴上的正值朝下。 但是,在三维坐标系中,原点位于呈现区域的中心,x 轴上的正值朝右,但是 y 轴上的正值朝上,z 轴上的正值从原点向外朝向观察者。

照相机

 

 

透视投影和正投影

 

关于TextureCoordinates(纹理坐标):

 
<MeshGeometry3D Positions="-250,-150,0 250,-150,0 250,150,0 -250,150,0"        TextureCoordinates="0,1 1,1 1,0 0,0"        TriangleIndices="0,1,2 0,2,3" />

 

 
上面这段MeshGeometry3D(用于生成3-D形状的三角形基元)对照图2三维坐标系会发现是个从左下角逆时针绘制的矩形。如果要将一个窗体UserControl纹理应用到Viewport2DVisual3D上,我们就需要合理的设置TextureCoordinates(纹理坐标)。对照图1二维坐标系,纹理坐标同样是由左下开始绘制的矩形。这样设置,纹理就可以显示正常了。

 
关于视角和距离的关系:
  
 
含义:

说明
A
视点
 
 

线
说明
BC
查看的目标宽度
bc
展示的视窗宽度
AD
视点到查看目标的距离
ad
视点到视窗的距离
 
 
角度
说明
cAb
视角(FieldOfView)
 
 
结论:
BD/bd=AD/Ad
 
我们如果想看到一个原样大小的窗体,就需要设置我的角cAb为90。同时设置AD长度为查看目标的一半宽度。
 
 
 
 
好不容易设置好Viewport3D,将UserControl作为窗体的查看对象,却发现虽然窗体大小一致,但是显示出的UserControl字体和控件却很模糊。当我们以3D模型渲染窗体时,WPF应该做了性能优化,然而我并不清楚如何开启高清模式= =。
怎么解决这个问题呢?我试了好久,发现并没有比较简单快捷的解决方法。没办法,只能采取一些小技巧来解决啦。
 
具体思路:
第一步:窗体呈现时,将UserControl实例化后直接呈现到页面最前端的展示面板上,此时Viewport3D内容为空。
第二部:触发页面翻转动画时,将最前的展示面板置空,UserControl实例剪切到Viewport3D里面。
第三步:动画执行完毕后再从Viewport3D里面将UserControl剪切到页面最前端的展示面板中。


 
 示例代码:
<Window x:Class="App3DWindow.MainWindow"    ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    ="http://schemas.microsoft.com/winfx/2006/xaml"    ="clr-namespace:App3DWindow"    ="clr-namespace:AsyncDelegate"    ="http://schemas.microsoft.com/expression/blend/2008"    ="http://schemas.open    Title="MainWindow"    Width="500"    Height="310"    AllowsTransparency="True"    Background="Transparent"    Loaded="MainWindow_OnLoaded"    WindowStyle="None"    WindowStartupLocation="CenterScreen"    mc:Ignorable="d">  <Window.Resources>    <Storyboard x:Key="Turn2ConfigViewStoryboard">      <Rotation3DAnimationUsingKeyFrames Storyboard.TargetName="containerUIElement3D" Storyboard.TargetProperty="(Visual3D.Transform).(Transform3DGroup.Children)[2].(RotateTransform3D.Rotation)">        <EasingRotation3DKeyFrame KeyTime="0:0:2">          <EasingRotation3DKeyFrame.EasingFunction>            <QuinticEase EasingMode="EaseOut" />          </EasingRotation3DKeyFrame.EasingFunction>          <EasingRotation3DKeyFrame.Value>            <AxisAngleRotation3D Angle="180" Axis="0,1,0" />          </EasingRotation3DKeyFrame.Value>        </EasingRotation3DKeyFrame>      </Rotation3DAnimationUsingKeyFrames>    </Storyboard>    <Storyboard x:Key="Turn2DownloadViewStoryboard">      <Rotation3DAnimationUsingKeyFrames Storyboard.TargetName="containerUIElement3D" Storyboard.TargetProperty="(Visual3D.Transform).(Transform3DGroup.Children)[2].(RotateTransform3D.Rotation)">        <EasingRotation3DKeyFrame KeyTime="0:0:2">          <EasingRotation3DKeyFrame.EasingFunction>            <QuinticEase EasingMode="EaseOut" />          </EasingRotation3DKeyFrame.EasingFunction>          <EasingRotation3DKeyFrame.Value>            <AxisAngleRotation3D Angle="360" Axis="0,1,0" />          </EasingRotation3DKeyFrame.Value>        </EasingRotation3DKeyFrame>      </Rotation3DAnimationUsingKeyFrames>    </Storyboard>    <!-- 相机 -->    <PerspectiveCamera x:Key="PerspectiveCamera"              FieldOfView="90"              LookDirection="0,0,-1"              NearPlaneDistance="1"              Position="0,0,250"              UpDirection="0,1,0" />     <OrthographicCamera x:Key="OrthographicCamera"              Width="500"              LookDirection="0,0,-1"              Position="0,0,250"              UpDirection="0,1,0" />  </Window.Resources>  <Grid Background="Transparent">    <Viewport3D Margin="0">      <Viewport3D.Camera>        <!-- 相机 -->        <PerspectiveCamera x:Name="PerspectiveCamera"                  FieldOfView="90"                  LookDirection="0,0,-1"                  NearPlaneDistance="1"                  Position="0,0,250"                  UpDirection="0,1,0" />      </Viewport3D.Camera>      <Viewport3D.Children>        <ContainerUIElement3D x:Name="containerUIElement3D">          <ContainerUIElement3D.Transform>            <Transform3DGroup>              <TranslateTransform3D OffsetX="0"                         OffsetY="0"                         OffsetZ="0" />              <ScaleTransform3D ScaleX="1"                       ScaleY="1"                       ScaleZ="1" />              <RotateTransform3D d:EulerAngles="0,0,0">                <RotateTransform3D.Rotation>                  <AxisAngleRotation3D Angle="0" Axis="0,1,0" />                </RotateTransform3D.Rotation>              </RotateTransform3D>              <TranslateTransform3D OffsetX="0"                         OffsetY="0"                         OffsetZ="0" />              <TranslateTransform3D OffsetX="0"                         OffsetY="0"                         OffsetZ="0" />            </Transform3DGroup>          </ContainerUIElement3D.Transform>           <!-- 正面视角 -->          <Viewport2DVisual3D x:Name="FrontViewport2DVisual3D">            <Viewport2DVisual3D.Transform>              <Transform3DGroup>                <TranslateTransform3D OffsetX="0"                           OffsetY="0"                           OffsetZ="0" />                <ScaleTransform3D ScaleX="1"                         ScaleY="1"                         ScaleZ="1" />                <RotateTransform3D d:EulerAngles="0,0,0">                  <RotateTransform3D.Rotation>                    <AxisAngleRotation3D Angle="0" Axis="0,0,0" />                  </RotateTransform3D.Rotation>                </RotateTransform3D>                <TranslateTransform3D OffsetX="0"                           OffsetY="0"                           OffsetZ="0" />                <TranslateTransform3D OffsetX="0"                           OffsetY="0"                           OffsetZ="0" />              </Transform3DGroup>            </Viewport2DVisual3D.Transform>            <Viewport2DVisual3D.Geometry>              <MeshGeometry3D Positions="-250,-150,0 250,-150,0 250,150,0 -250,150,0"                      TextureCoordinates="0,1 1,1 1,0 0,0"                      TriangleIndices="0,1,2 0,2,3" />            </Viewport2DVisual3D.Geometry>            <Viewport2DVisual3D.Material>              <DiffuseMaterial Viewport2DVisual3D.IsVisualHostMaterial="True" />            </Viewport2DVisual3D.Material>            <Viewport2DVisual3D.Visual>              <app3DWindow:DownloadWindow x:Name="DownloadWindowPart"                            Width="500"                            Height="300"                            Background="White"                            SnapsToDevicePixels="True" />            </Viewport2DVisual3D.Visual>          </Viewport2DVisual3D>          <!-- 背面视角 -->          <Viewport2DVisual3D x:Name="BackViewport2DVisual3D">            <Viewport2DVisual3D.Transform>              <Transform3DGroup>                <TranslateTransform3D OffsetX="0"                           OffsetY="0"                           OffsetZ="0" />                <ScaleTransform3D ScaleX="1"                         ScaleY="1"                         ScaleZ="1" />                <RotateTransform3D d:EulerAngles="0,0,0">                  <RotateTransform3D.Rotation>                    <AxisAngleRotation3D Angle="0" Axis="0,0,0" />                  </RotateTransform3D.Rotation>                </RotateTransform3D>                <TranslateTransform3D OffsetX="0"                           OffsetY="0"                           OffsetZ="0" />                <TranslateTransform3D OffsetX="0"                           OffsetY="0"                           OffsetZ="0" />              </Transform3DGroup>            </Viewport2DVisual3D.Transform>            <Viewport2DVisual3D.Geometry>              <MeshGeometry3D Positions="-250,-150,0 250,-150,0 250,150,0 -250,150,0"                      TextureCoordinates="1,1 0,1 0,0 1,0  "                      TriangleIndices="0,3,2 0,2,1" />            </Viewport2DVisual3D.Geometry>            <Viewport2DVisual3D.Material>              <DiffuseMaterial Viewport2DVisual3D.IsVisualHostMaterial="True" />            </Viewport2DVisual3D.Material>            <Viewport2DVisual3D.Visual>              <app3DWindow:ProxyConfigView x:Name="ProxyConfigViewPart"                             Width="500"                             Height="300"                             Background="White"                             SnapsToDevicePixels="True" />            </Viewport2DVisual3D.Visual>          </Viewport2DVisual3D>        </ContainerUIElement3D>         <ModelVisual3D>          <ModelVisual3D.Content>            <!-- 光源 -->            <AmbientLight x:Name="ViewLight" />          </ModelVisual3D.Content>        </ModelVisual3D>      </Viewport3D.Children>    </Viewport3D>    <Grid x:Name="DisplayGrid">      <Grid.RowDefinitions>        <RowDefinition Height="40" />        <RowDefinition Height="*" />      </Grid.RowDefinitions>      <UserControl x:Name="DisPlayControl"             Grid.Row="0"             Grid.RowSpan="2" />      <!--<Border x:Name="Part_Drag"          Grid.Row="0"          Background="AliceBlue"          PreviewMouseLeftButtonDown="DisPlayControl_OnPreviewMouseLeftButtonDown" />-->    </Grid>  </Grid></Window>

using System.Windows;using System.Windows.Controls;using System.Windows.Input;using System.Windows.Media.Animation; namespace App3DWindow{  /// <summary>  /// MainWindow.xaml 的交互逻辑  /// </summary>  public partial class MainWindow : Window  {    public MainWindow()    {      InitializeComponent();    }    /// <summary>    /// 载入时进行模糊情况特殊处理    /// </summary>    /// <param name="sender"></param>    /// <param name="e"></param>    private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)    {      //return;      SetDownloadWindowDisplayMode();      var turn2ConfigViewStoryboard = this.TryFindResource("Turn2ConfigViewStoryboard") as Storyboard;      if (turn2ConfigViewStoryboard != null)      {        turn2ConfigViewStoryboard.Completed += (s, e1) =>        {//动画执行完成切换展示模式          SetConfigViewDisplayMode();          SetDownloadWindowTurningMode();        };        turn2ConfigViewStoryboard.CurrentTimeInvalidated += (s, e1) =>        {//动画执行时切换成翻转模式          SetDownloadWindowTurningMode();        };      };      var turn2DownloadViewStoryboard = this.TryFindResource("Turn2DownloadViewStoryboard") as Storyboard;      if (turn2DownloadViewStoryboard != null)      {        turn2DownloadViewStoryboard.Completed += (s, e1) =>        {//动画执行完成切换展示模式          SetDownloadWindowDisplayMode();          SetConfigViewTurningMode();        };        turn2DownloadViewStoryboard.CurrentTimeInvalidated += (s, e1) =>        {//动画执行时切换成翻转模式          SetConfigViewTurningMode();        };      };    }    /// <summary>    /// 设置下载页面进入展示模式    /// </summary>    private void SetDownloadWindowDisplayMode()    {      //var container = DownloadWindowPart.Parent as Viewport2DVisual3D;      //if (container == null) return;      //container.Visual = null;      if (FrontViewport2DVisual3D.Visual==(DownloadWindowPart))      {        FrontViewport2DVisual3D.Visual = null;      }      DisPlayControl.Content = DownloadWindowPart;    }    /// <summary>    /// 设置配置页面进入展示模式    /// </summary>    private void SetConfigViewDisplayMode()    {      //var container = ProxyConfigViewPart.Parent as Viewport2DVisual3D;      //if (container == null) return;      //container.Visual = null;      if (BackViewport2DVisual3D.Visual==(ProxyConfigViewPart))      {        BackViewport2DVisual3D.Visual = null;      }      DisPlayControl.Content = ProxyConfigViewPart;    }    /// <summary>    /// 设置下载页面进入翻转模式    /// </summary>    private void SetDownloadWindowTurningMode()    {      var container = DownloadWindowPart.Parent as UserControl;      if (container == null) return;      container.Content = null;      FrontViewport2DVisual3D.Visual = DownloadWindowPart;    }    /// <summary>    /// 设置配置页面进入翻转模式    /// </summary>    private void SetConfigViewTurningMode()    {      var container = ProxyConfigViewPart.Parent as UserControl;      if (container == null) return;      container.Content = null;      BackViewport2DVisual3D.Visual = ProxyConfigViewPart;    }    /// <summary>    /// 支持拖拽    /// </summary>    /// <param name="sender"></param>    /// <param name="e"></param>    private void DisPlayControl_OnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)    {      this.DragMove();    }  }}

 


 呈现效果:
效果见下图,翻转动画执行完毕后不再模糊。