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

原文: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实体。

演示程序 源代码

时间: 2024-08-04 05:04:16

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

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

原文:在WPF中使用PlaneProjection模拟动态3D效果 虽然在WPF中也集成了3D呈现的功能,在简单的3D应用中,有时候并不需要真实光影的3D场景.毕竟使用3D引擎会消耗很多资源,有时候使用各种变换和假的阴影贴图也能设计出既省资源,又有很好用户体验的“伪”3D界面. 在Silverlight中,因为性能问题,一般并不使用真3D引擎,微软为Silverlight提供了System.Windows.Media.PlaneProjection 类,用投影变换来模拟3D的效果. 下面让我们看

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

原文:WPF换肤之八:创建3D浏览效果 上节中,我们展示了WPF中的异步以及界面线程交互的方式,使得应用程序的显示更加的流畅.这节我们主要讲解如何设计一个具有3D浏览效果的天气信息浏览器. 效果显示 下面我们看截图: 是不是能够感受到一种与众不同的感觉.如果你能够感受到它的与众不同,这也是我本节所要达到的目标. 实现方式 上面的只是一个简单的3D图形,它的产生需要依赖于WPF中的MeshGeometry3D对象,这个对象按照微软官方的解释就是用于生成3D形状的三角形基元,它有三个比较重要的属性:

Dgame3D——开源3D网页游戏引擎

资源介绍: 创建一个主类 public class Main extends Sprite在构造函数中监听舞台的初始化if (stage) init();else addEventListener(Event.ADDED_TO_STAGE, init);在init函数中创建Context3D创建成功会有一个回调事件,在事件中创建dGame3DSystem,创建一个游戏类Game,最后再创建一个timer用于游戏类的主循环 dGame3DSystem.CreateContext3D( stage

CSS 3D transform(CSS的3D变换)

src1:好吧,CSS3 3D transform变换,不过如此! 评价:图文并茂地解释 CSS 3D transform 的基本概念及原理,超级通俗易懂,读后简直醍醐灌顶啊!!!幽默的程序员 笔记: 一.4个概念 1.突破口:三个方法  3D transform 中的三个方法: (1)rotateX(angle):正面推倒 (2)rotateY(angle):左右转 (3)rotateZ(angle):横抱躺着 2.必不可少的perspective(透视.视角) 没透视,不3D CSS 3D

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

一.引言 关于WPF早在一年前就已经看过<深入浅出WPF>这本书,当时看完之后由于没有做笔记,以至于我现在又重新捡起来并记录下学习的过程,本系列将是一个WPF快速入门系列,主要介绍WPF中主要的几个不同的特性,如依赖属性.命令.路由事件等. 在正式介绍之前,我还想分享下为什么我又要重新捡起来WPF呢?之前没有记录下来的原来主要是打算走互联网方向的,后面发现互联网方向经常加班,又累,有时候忙的连自己写了什么都不知道的,所以后面机缘巧合地进了一家外企,在外企不像互联网行业那样,比较清楚,有更多的时

在自遮挡下的单目图像3D姿态估计 Monocular Image 3D Human Pose Estimation under Self-Occlusion (ICCV 13)

Monocular Image 3D Human Pose Estimationunder Self-Occlusion (ICCV 13) 在自遮挡下的单目图像3D姿态估计 摘要:文中提出在单张图片中3D姿态自动重建的方法.人体关节.易产生幻觉的身体部位的存在,杂乱的背景,都将导致人体姿态判断的歧义性,这都说明这不是一个简单的问题.研究者研究了许多基于运动和阴影的方法,为了减小歧义性,并对3D姿态进行重建.我们算法的关键思想就是增加运动和方向限制.前一个是在3D模型映射到输入图像时增加的限制,

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

<!DOCTYPE> <html lang='en'> <head> <title>3-Highcharts 3D图之3D柱状图分组叠堆3D图</title> <meta http-equiv="content-type" content="text/html;charset=utf-8"> <script src="../jquery-2.1.4/jquery.min.js&q

WPF加载HTML、WPF与JavaScript交互

目录 一.WebBrowser加载远程网页 二.WebBrowser加载本地网页,注:不可以加载本地样式CSS和脚本JS文件 三.WebBrowser隐藏网页的JavaScript错误 四.网页屏蔽鼠标右键.Ctrl+N.Shift+F10.F11.F5刷新.退格键 五.WPF程序与网页JavaScript交互 六.创建服务器,提供数据接口.Script.CSS文件 一.WebBrowser加载远程网页 wbrExam.Source = new Uri("http://cnblogs.com/s

WPF换肤之三:WPF中的WndProc

原文:WPF换肤之三:WPF中的WndProc 在上篇文章中,我有提到过WndProc中可以处理所有经过窗体的事件,但是没有具体的来说怎么可以处理的. 其实,在WPF中,要想利用WndProc来处理所有的事件,需要利用到SourceInitialized  Event,首先需要创建一个HwndSource对象,然后利用其AddHook方法来将所有的windows消息附加到一个现有的事件中,这个就是WndProc. void WSInitialized(object sender, EventAr