原文:WPF 3D 小小小小引擎 - ·WPF 3D变换应用

WPF可以提供的3D模型使我们可以轻松地创建3D实体,虽然目前来看还很有一些性能上的问题,不过对于一些简单的3D应用应该是可取的,毕竟其开发效率高,而且也容易上手。

下面给大家演示的是使用在WPF 3D上实现视角变换,通过鼠标拖动来变换观察视角,通过滚轮来放缩视距。

有关3D的基础知识可以参考MSDN文档:三维图形概述

首先创建一个3D立方体,立方体是由六个面构成(F1, F2 ....F6)其XAML代码如下:

<Viewport3D>

<Viewport3D.Camera>

<PerspectiveCamera Position="8,8,8" LookDirection="-1 -1 -1" FieldOfView="75" UpDirection="-1 1 -1" x:Name="camera"></PerspectiveCamera>

</Viewport3D.Camera>

<Viewport3D.Children>

<ModelVisual3D x:Name="light">

<ModelVisual3D.Content>

<AmbientLight />

</ModelVisual3D.Content>

</ModelVisual3D>

<ModelVisual3D x:Name="magicCube">

<ModelVisual3D.Content>

<!--    0: 0,0,0    1: 0,0,2    2: 2,0,2    3: 2,0,0    4: 2,2,0    5: 0,2,0    6: 0,2,2    7: 2,2,2    -->

<Model3DGroup x:Name="cube">

<Model3DGroup.Transform>

<TranslateTransform3D OffsetX="-1" OffsetY="-1" OffsetZ="-1" />

</Model3DGroup.Transform>

<!--F1: 0,3,2,1-->

<GeometryModel3D x:Name="F1">

<GeometryModel3D.Material>

<DiffuseMaterial Brush="Blue"/>

</GeometryModel3D.Material>

<GeometryModel3D.Geometry>

<MeshGeometry3D Positions="0,0,0 2,0,0 2,0,2 0,0,2" TriangleIndices="0,1,2 0,2,3"></MeshGeometry3D>

</GeometryModel3D.Geometry>

</GeometryModel3D>

<!--F2: 0,1,6,5-->

<GeometryModel3D x:Name="F2">

<GeometryModel3D.Material>

<DiffuseMaterial Brush="Green"/>

</GeometryModel3D.Material>

<GeometryModel3D.Geometry>

<MeshGeometry3D Positions="0,0,0 0,0,2 0,2,2 0,2,0" TriangleIndices="0 1 2 0 2 3"></MeshGeometry3D>

</GeometryModel3D.Geometry>

</GeometryModel3D>

<!--F3: 4,5,6,7-->

<GeometryModel3D x:Name="F3">

<GeometryModel3D.Material>

<DiffuseMaterial Brush="Red"/>

</GeometryModel3D.Material>

<GeometryModel3D.Geometry>

<MeshGeometry3D Positions="2,2,0 0,2,0 0,2,2 2,2,2" TriangleIndices="0 1 2 0 2 3"></MeshGeometry3D>

</GeometryModel3D.Geometry>

</GeometryModel3D>

<!--F4: 2,3,4,7-->

<GeometryModel3D x:Name="F4">

<GeometryModel3D.Material>

<DiffuseMaterial Brush="Yellow"/>

</GeometryModel3D.Material>

<GeometryModel3D.Geometry>

<MeshGeometry3D Positions="2,0,2 2,0,0 2,2,0 2,2,2" TriangleIndices="0 1 2 0 2 3" TextureCoordinates="0,0 0,1 1,1 1,0">

</MeshGeometry3D>

</GeometryModel3D.Geometry>

</GeometryModel3D>

<!--F5: 1,2,7,6-->

<GeometryModel3D x:Name="F5">

<GeometryModel3D.Material>

<DiffuseMaterial Brush="White"/>

</GeometryModel3D.Material>

<GeometryModel3D.Geometry>

<MeshGeometry3D Positions=" 0,0,2 2,0,2 2,2,2 0,2,2" TriangleIndices="0 1 2 0 2 3"></MeshGeometry3D>

</GeometryModel3D.Geometry>

</GeometryModel3D>

<!--F6: 0,5,4,3-->

<GeometryModel3D x:Name="F6">

<GeometryModel3D.Material>

<DiffuseMaterial Brush="Orange"/>

</GeometryModel3D.Material>

<GeometryModel3D.Geometry>

<MeshGeometry3D Positions=" 0,0,0 0,2,0 2,2,0 2,0,0" TriangleIndices="0 1 2 0 2 3"></MeshGeometry3D>

</GeometryModel3D.Geometry>

</GeometryModel3D>

</Model3DGroup>

</ModelVisual3D.Content>

</ModelVisual3D>

</Viewport3D.Children>

</Viewport3D>

在Viewport中用六个面构成一个立方体, 每一个面都是一个GeometryModel3D。

下面就是如何来实现通过鼠标拖动来变换视角的功能。首先给Window对象添加几个有关的鼠标的事件:MouseMove、MouseLeftButtonDown和MouseWheel。

<Window x:Class="MagicCube.MainWindow"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

Title="MainWindow" Height="295" Width="525" Background="Black"

MouseMove="Viewport3D_MouseMove"

        MouseLeftButtonDown="Viewport3D_MouseLeftButtonDown"

        MouseWheel="Viewport3D_MouseWheel"

KeyDown="Window_KeyDown">

<Viewport3D …>

</Window>

说明一下使用到的几个变量:

其中MouseLeftButtonDown是用来获取鼠标在进入拖动状态之前的位置,这样我们就可以根据鼠标位置的改变类变换视角。
Point mouseLastPosition;

private void Viewport3D_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)

{

mouseLastPosition = e.GetPosition(this);

}

下面是MouseMove事件,实现视角的变换。首先鼠标在拖动的过程中,可能发生水平方向上的变化和垂直方向上的变化,所以,我们将对不同的变化方向进行不同的变换。这里我将水平变换和垂直变换已经分别封装至两个方法中:HorizontalTransform(水平变换)和VerticalTransform(垂直变换)

private void Viewport3D_MouseMove(object sender, MouseEventArgs e)

{

if (Mouse.LeftButton == MouseButtonState.Pressed)

{

Point newMousePosition = e.GetPosition(this);

if (mouseLastPosition.X != newMousePosition.X)

{

HorizontalTransform(mouseLastPosition.X < newMousePosition.X, mouseDeltaFactor);//水平变换

}

if (mouseLastPosition.Y != newMousePosition.Y)// change position in the horizontal direction

{

VerticalTransform(mouseLastPosition.Y > newMousePosition.Y, mouseDeltaFactor);//垂直变换

}

mouseLastPosition = newMousePosition;

}

}

  接下来我们就来看一下这两个变换方法的具体实现:

垂直变换:

private void VerticalTransform(bool upDown, double angleDeltaFactor){    Vector3D postion = new Vector3D(camera.Position.X, camera.Position.Y, camera.Position.Z);    Vector3D rotateAxis = Vector3D.CrossProduct(postion, camera.UpDirection);    RotateTransform3D rt3d = new RotateTransform3D();    AxisAngleRotation3D rotate = new AxisAngleRotation3D(rotateAxis, angleDeltaFactor * (upDown ? -1 : 1));    rt3d.Rotation = rotate;    Matrix3D matrix = rt3d.Value;    Point3D newPostition = matrix.Transform(camera.Position);    camera.Position = newPostition;    camera.LookDirection = new Vector3D(-newPostition.X, -newPostition.Y, -newPostition.Z);    //update the up direction    Vector3D newUpDirection = Vector3D.CrossProduct(camera.LookDirection, rotateAxis);    newUpDirection.Normalize();    camera.UpDirection = newUpDirection;}
水平变换:private void HorizontalTransform(bool leftRight, double angleDeltaFactor){    Vector3D postion = new Vector3D(camera.Position.X, camera.Position.Y, camera.Position.Z);    Vector3D rotateAxis = camera.UpDirection;    RotateTransform3D rt3d = new RotateTransform3D();    AxisAngleRotation3D rotate = new AxisAngleRotation3D(rotateAxis, angleDeltaFactor * (leftRight ? -1 : 1));    rt3d.Rotation = rotate;    Matrix3D matrix = rt3d.Value;    Point3D newPostition = matrix.Transform(camera.Position);    camera.Position = newPostition;    camera.LookDirection = new Vector3D(-newPostition.X, -newPostition.Y, -newPostition.Z);}

最后还有一个鼠标滚轮调节视距的变换,如下:

private void Viewport3D_MouseWheel(object sender, MouseWheelEventArgs e){    double scaleFactor = 3;    //120 near ,   -120 far    System.Diagnostics.Debug.WriteLine(e.Delta.ToString());    Point3D currentPosition = camera.Position;    Vector3D lookDirection = camera.LookDirection;//new Vector3D(camera.LookDirection.X, camera.LookDirection.Y, camera.LookDirection.Z);    lookDirection.Normalize();    lookDirection *= scaleFactor;    if (e.Delta == 120)//getting near    {        if ((currentPosition.X + lookDirection.X) * currentPosition.X > 0)        {            currentPosition += lookDirection;        }    }    if (e.Delta == -120)//getting far    {        currentPosition -= lookDirection;    }    Point3DAnimation positionAnimation = new Point3DAnimation();    positionAnimation.BeginTime = new TimeSpan(0, 0, 0);    positionAnimation.Duration = TimeSpan.FromMilliseconds(100);    positionAnimation.To = currentPosition;     positionAnimation.From = camera.Position;    positionAnimation.Completed += new EventHandler(positionAnimation_Completed);    camera.BeginAnimation(PerspectiveCamera.PositionProperty, positionAnimation, HandoffBehavior.Compose);}

有了这个小程序之后,我们以后如果需要制作WPF 3D实体,也可以通过它来360度全方位地观测构建的3D实体。

演示程序 源代码

WPF 3D 小小小小引擎 - ·WPF 3D变换应用的更多相关文章

  1. 在WPF中使用PlaneProjection模拟动态3D效果

    原文:在WPF中使用PlaneProjection模拟动态3D效果 虽然在WPF中也集成了3D呈现的功能,在简单的3D应用中,有时候并不需要真实光影的3D场景.毕竟使用3D引擎会消耗很多资源,有时候使 ...

  2. WPF换肤之八:创建3D浏览效果

    原文:WPF换肤之八:创建3D浏览效果 上节中,我们展示了WPF中的异步以及界面线程交互的方式,使得应用程序的显示更加的流畅.这节我们主要讲解如何设计一个具有3D浏览效果的天气信息浏览器. 效果显示 ...

  3. WPF: Creation of Text Labels for 3D Scene

    原文:WPF: Creation of Text Labels for 3D Scene 转载:http://www.codeproject.com/KB/WPF/WPF_Text3D.aspx Do ...

  4. 知名游戏引擎公司Havok发布免费3D移动游戏引擎“Project Anarchy”

    自EA发布“寒霜”引擎(Frostbite Engine)移动版后,知名游戏引擎公司Havok也发布了免费的3D移动游戏引擎“Project Anarchy”. 据悉,6月底时候,Intel旗下知名游 ...

  5. 3D Cube计算引擎加速运算

    3D Cube计算引擎加速运算 华为达芬奇架构的AI芯片Ascend910,同时与之配套的新一代AI开源计算框架MindSpore. 为什么要做达芬奇架构? AI将作为一项通用技术极大地提高生产力,改 ...

  6. WPF系列(1)WPF和XAML基础

    终于下定决心开始更新WPF一个系列的文章,这里主要是出于两个目的,一是自己对所学的知识有一个系统的总结,二十希望能对其他人有些帮助,如果您觉得我写的不好,欢迎提意见. 那么既然我要开始写WPF,那我们 ...

  7. WPF快速入门系列(1)——WPF布局概览

    一.引言 关于WPF早在一年前就已经看过<深入浅出WPF>这本书,当时看完之后由于没有做笔记,以至于我现在又重新捡起来并记录下学习的过程,本系列将是一个WPF快速入门系列,主要介绍WPF中 ...

  8. 3-Highcharts 3D图之3D柱状图分组叠堆3D图

    <!DOCTYPE> <html lang='en'> <head> <title>3-Highcharts 3D图之3D柱状图分组叠堆3D图</ ...

  9. WPF换肤之三:WPF中的WndProc

    原文:WPF换肤之三:WPF中的WndProc 在上篇文章中,我有提到过WndProc中可以处理所有经过窗体的事件,但是没有具体的来说怎么可以处理的. 其实,在WPF中,要想利用WndProc来处理所 ...

随机推荐

  1. date 命令

    在linux环境中,不管是编程还是其他维护,时间是必不可少的,也经常会用到时间的运算,熟练运用date命令来表示自己想要表示的时间,肯定可以给自己的工作带来诸多方便.1.命令格式: date [参数] ...

  2. SQL Server(高级) 关键字的使用 二

    二, 高级 关键字 -- 使用介绍 8,Top 的使用(Top子句返回记录的数目) select top number|percent column_name(s) from table_name 或 ...

  3. CS0016: 未能写入输出文件“c:\windows\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\data\34aae060\b7daa87d\App_Web_addadvice.aspx.cdcab7d2.ekhlcbjd.dll”--“目录名无效。 ”

    产生原因: 应用程序运行时产生的临时文件需要存放到c:"windows"temp 文件夹下 而运行基于microsoft .net framework 框架下的应用程序 需要对te ...

  4. [getLongestLength] 加和为0的最长子串长度

    点击这里查看原文 假设一个数组仅仅由1和-1组成,求该数组的和为0的最长子串的长度. 例如: {1,-1,1,-1,1,1,1} 输出:4. 昨天机试的时候做到这道题,不会做,今天思考一下. 普通的解 ...

  5. 踩过的坑系列之InputStream.read(byte[])方法

    项目之前都是好好的,最近现场那边出现一个问题,报错不是合法的json字符串,这个json字符串是通过http请求访问获得的. 通过直接在浏览器上直接访问http这个请求,发现返回的json也是完全正确 ...

  6. fuser 命令概述

    fuser 概述 fuser命令是用来显示所有正在使用着指定的file, file system 或者 sockets的进程信息. 例一: #fuser –m –u /mnt/usb1 /mnt/us ...

  7. .NET平台开源项目速览-最快的对象映射组件Tiny Mapper之项目实践

    心情小札:近期换了工作,苦逼于22:00后下班,房间一篇狼藉~ 小翠鄙视到:"你就适合生活在垃圾堆中!!!" 晚上浏览博客园 看到一篇非常实用的博客:.NET平台开源项目速览(14 ...

  8. 为什么Laravel是最成功的PHP框架?

    Laravel 是一个有着美好前景的年轻框架,它的社区充满着活力,相关的文档和教程完整而清晰,并为快速.安全地开发现代应用程序提供了必要的功能.在近几年对PHP 框架流行度的统计中,Laravel始终 ...

  9. Nginx禁止通过IP,未绑定域名访问服务器

    这几天查看CNZZ统计后台看到,我的IP被两个未知的域名绑定了,为了避免被天朝和谐掉, 可以在Nginx上设置禁止通过IP访问服务器,只能通过绑定域名访问(同时设置未绑定域名返回500错误或者跳转到我 ...

  10. org.springframework.web.servlet.view.InternalResourceViewResolver

    http://blog.csdn.net/superdog007/article/details/28857495 我们在controller里面经常这样return一个ModelAndView: r ...