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"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:app3DWindow="clr-namespace:App3DWindow"
        xmlns:asyncDelegate="clr-namespace:AsyncDelegate"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        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();
        }
    }
}

呈现效果:

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

时间: 2024-07-30 02:41:48

WPF Viewport3D 解决透视模式时窗体模糊的相关文章

如何解决卸载McAfee时出现“处于托管模式时无法删除”问题(转)

问题现象: 这几天在为客户终端换装杀毒软件时出现这么一个问题:在控制面板的添加或删除程序里面将“McAfee VirusScan Enterprise和 McAfee AntiSpyware Enterprise Module”卸载后,却无法卸载“McAfee agent”,总是提示“处于托管模式时无法删除”. 问题分析: 其实这是因为McAfee杀毒软件的CMA程序在作怪,而这个CMA却并不会在添加或删除程序列表里面显示,且它会占用一个服务. 解决方法: 在 McAfee 默认安装目录下,有一

单件模式+打开窗体+窗体构造函数参数

利用单件模式避免重复打开窗体,窗体为无参数构造函数模式. 注:该博客中有自动关闭窗体的方法 http://www.cnblogs.com/zfanlong1314/p/3567308.html 为了打开窗体时传入参数,可以改变方法的传递参数,本人修改后代码如下 /// <summary> /// 泛型实现窗体实例单件化/// </summary> /// <typeparam name="T">窗体类</typeparam> public

WPF教程:MVVM模式的理解与应用

一.  什么是MVVM模式 MVVM是Model-View-ViewModel的简写.微软的WPF带来了新的技术体验,如Silverlight.音频.视频.3D.动画--.这导致了软件UI层更加细节化.可定制化.同时,在技术层面,WPF也带来了诸如Binding.Dependency Property.Routed Events.Command.DataTemplate.ControlTemplate等新特性.MVVM(Model-View-ViewModel)框架的由来便是MVP(Model-

WPF ContextMenu 在MVVM模式中绑定 Command及使用CommandParameter传参

原文:WPF ContextMenu 在MVVM模式中绑定 Command及使用CommandParameter传参 ContextMenu无论定义在.cs或.xaml文件中,都不继承父级的DataContext,所以如果要绑定父级的DataContext,直接DataContext=“{Binding}”是行不通的 不能绑父级,但是能绑资源 第一步:定义一个中间类用来做资源对象 1 public class BindingProxy : Freezable 2 { 3 #region Over

基于ASP.NET WPF技术及MVP模式实战太平人寿客户管理项目开发(Repository模式)

亲爱的网友,我这里有套课程想和大家分享,如果对这个课程有兴趣的,可以加我的QQ2059055336和我联系. 课程背景 本课程是教授使用WPF.ADO.NET.MVVM技术来实现太平人寿保险有限公司保险客户管理系统,是学习WPF开发中的一门主打课程之一. WPF是一个框架,它供程序员开发出媲美Mac程序的酷炫界面. Blend是一种工具,可以在美工板上绘制形状.路径和控件,然后修改其外观和行为,从而直观地设计应用程序 Repository\MVVM\MVP设计模式是WPF常用的系统架构 Auto

数据库调优教程(十) 【精华章节】解决like ’%str’ 时索引不被使用的4种方法

三.           索引 7.      解决like'%str'不使用模糊查询的4种方法 上一讲最后说了,只要模糊查询的模糊值在字符串前面,则不会使用索引,'%aaa'和'_aaa'都不会! 如下 应该说这是Mysql给程序员们开的一个玩笑.要是我的表数据量很大,而且又需要使用like'%%'这样的模糊查询来检索时,该怎么办?? 接下来,笔者将会给大家分享解决这个问题的四种方法! 1)    Select主键 只要Select的字段刚好是主键,那么就会使用到索引(只对innodb数据库有

第5篇 WPF C# 数据绑定Model-View-ViewModel模式

第5篇  WPF C# 数据绑定Model-View-ViewModel模式 参考资料: John Sharp:<Microsoft Visual C# 2013 Step by Step> 周 靖 译:John Sharp<Visual C# 2012从入门到精通> 前言 Model-View-ViewModel模式即MVVM模式编程涉及五个文件: 1.MainWindow.xaml文件 UI界面文件 2.MainWindow.xaml.cs文件  UI架构文件 3.ViewMo

使用XmlInclude解决WebService调用时无法识别子类的异常

一.定义抽象类及子类,WebMethod实际返回子类参数 //使用XmlInclude解决WebService调用时无法识别子类的异常 [System.Xml.Serialization.XmlInclude(typeof(WageEmploeyee)), System.Xml.Serialization.XmlInclude(typeof(Boss))] public abstract class EmployeeData { //Required by XmlSerializer publi

解决git Push时请求username和password,而不是ssh-key验证

转载自:https://blog.lowstz.org/posts/2011/11/23/why-git-push-require-username-password-github/ 之前开始用github时是在ubuntu下按着官方的新手指南搞定的.但最近一直在用fedora,所以也想在fedora下用github,配置的时候很顺利,就是在git push的每次都需要输入username和password,而我是配置好公钥登陆的.用ssh -T [email protected] 也是成功用公