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-09-13 21:16:55

WPF 3D 小小小小引擎 - &#183;WPF 3D变换应用的相关文章

3D手机游戏引擎Project Anarchy免费下载使用

&http://www.aliyun.com/zixun/aggregation/37954.html">nbsp;   免费3D手机游戏引擎Project Anarchy今日发布beta版,可以下载使用.Havok是英特尔的一家子公司,专注于中间件的开发,今天在GDC上透露其正在开发一个点对点的3D手机游戏引擎,这个引擎完全免费,今日已经发布beta版,可以下载使用. Anarchy Project是一个跨平台的引擎和工具包,是为手机游戏开发商量身打造的,Havok承诺此软件下载

2000条你应知的WPF小姿势 基础篇&lt;22-27 WPF生命周期, 基础类等&gt;

原文:2000条你应知的WPF小姿势 基础篇<22-27 WPF生命周期, 基础类等> 端午长假在家陪着女朋友, 幸福感满满,生活对于一只饱经忧患的程序猿来说也是非常重要的,也就暂时没有更新博客.休假结束,回归奋斗的日子了,开始继续更新WPF系列. 在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师.最为出色的是他维护了两个博客:2,000Things You Should Know About C#  和 2,000 Things You Should Kn

2000条你应知的WPF小姿势 基础篇&lt;69-73 WPF Freeze机制和Template&gt;

原文:2000条你应知的WPF小姿势 基础篇<69-73 WPF Freeze机制和Template> 在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师.最为出色的是他维护了两个博客:2,000Things You Should Know About C#  和 2,000 Things You Should Know About WPF .他以类似微博式的150字简短语言来每天更新一条WPF和C#重要又容易被遗忘的知识.很希望能够分享给大家. 本系列我不仅

《玩转3D打印》——1.4节3D打印机的选购

1.4 3D打印机的选购 玩转3D打印 现在3D打印机拥有多种品牌和型号,不同品牌和型号的3D打印机多采用了不同的打印技术,其应用领域也有所差异,用户在选用3D打印机时更多的需要考虑自己的应用需求.成本等方面的信息. 1.4.1 选购参数 下面为大家介绍一些关键的3D打印机参数,在购买3D打印机的时候应该根据自己的需求,着重考虑相应的参数. 1.打印尺寸 打印尺寸是指3D打印机能打印的最大体积,是由3D打印机的打印区域大小决定的.一般用"长×宽×高"的参数来表示一个3D打印机的打印尺寸

WPF界面里拖动自定义控件,WPF界面并没有后台代码。

问题描述 WPF界面里拖动自定义控件,WPF界面并没有后台代码. 我的控件已经写好了,是一个虚拟键盘,现在的做法是获取textbox的焦点,判断控件与界面之间的大小关系使其能在固定的位置显示,但现在我想要实现其能在界面上自由拖动/移动,暂时没有想到什么好的办法.网上有说用mousedown等函数来控制,但那些需要自界面后台代码中实现,现在界面是没有后台代码的,不知道如何实现,希望能有大神指教一下.谢谢! 补充一点键盘的前台代码:

《玩转3D打印》——1.1节3D打印的前世今生

1.1 3D打印的前世今生 玩转3D打印 3D打印(3D Printing),即快速成型技术的一种,它是一种以数字模型文件为基础,运用粉末状金属或者塑料等可黏合材料,通过逐层打印的方式来构造物体的技术.3D打印通常采用数字技术材料打印机来实现.过去3D打印技术常在模具制造.工业设计等领域用于制造模型,现在正逐渐用于一些产品的直接制造,已经有使用这种技术直接生产的零部件.该技术在珠宝.鞋类.工业设计.建筑.工程和施工(AEC).汽车.航空航天.牙科和医疗产业.教育.地理信息系统.土木工程.武器制造

《玩转3D打印》——第1章3D打印那些事儿

1 3D打印那些事儿 玩转3D打印 人猿相揖别,是因为古人能够手工制造工具并且使用:今人区别于古人,是因为能够用机器自动化大规模制造工具.人类进化至今,一个崭新的文明标志就是能够用机器制造机器.从某种意义上说,当前被赋予无限想象力的3D打印机正是这种能够制造机器的机器. 本章导读: 3D打印技术成长史和现状 3D打印的原理及打印耗材 3D打印的相对优势 3D打印机导购

2000条你应知的WPF小姿势 基础篇&lt;28-33 WPF启动故事&gt;

原文:2000条你应知的WPF小姿势 基础篇<28-33 WPF启动故事> 在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师.最为出色的是他维护了两个博客:2,000Things You Should Know About C#  和 2,000 Things You Should Know About WPF .他以类似微博式的150字简短语言来每天更新一条WPF和C#重要又容易被遗忘的知识.Follow他的博客也有一段日子了,很希望能够分享给大家. 本系

《玩转3D打印》——1.2节3D打印的原理及材质

1.2 3D打印的原理及材质 玩转3D打印 1.2.1 3D打印原理 3D打印技术每一层的打印过程分为两步.首先在需要的区域喷洒一种特殊胶水,胶水液滴本身很小,且不易扩散.然后是喷洒一层均匀的粉末,粉末遇到胶水会迅速固化黏结,而没有胶水的区域仍保持松散状态.这样在一层胶水一层粉末的交替下,实体模型将会被"打印"成型,打印完毕后只要扫除松散的粉末即可"刨"出模型,而剩余的粉末还可以循环利用. 3D打印耗材由传统的墨水.纸张转变为胶水.粉末,当然胶水和粉末都是经过处理的