WPF 3D变换应用

简介: 原文:WPF 3D变换应用 WPF可以提供的3D模型使我们可以轻松地创建3D实体,虽然目前来看还很有一些性能上的问题,不过对于一些简单的3D应用应该是可取的,毕竟其开发效率高,而且也容易上手。         下面给大家演示的是使用在WPF 3D上实现视角变换,通过鼠标拖动来变换观察视角,通过滚轮来放缩视距。
原文: WPF 3D变换应用

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

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

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

 <Viewport3D>
        <Viewport3D.Camera>
            <!--<camera Position="15,15,15" LookDirection="-1,-1,-1" Width="15"></camera>-->
            <!--<camera Position="-5,-5,-5" LookDirection="1,1,1" Width="10" x:Name="camera"></camera>-->
            <!--<PerspectiveCamera Position="-5,-5,-5" LookDirection="1 1 1" FieldOfView="90"></PerspectiveCamera>-->
            <!--<PerspectiveCamera Position="-4,-4,-4" LookDirection="1 1 1" FieldOfView="75" x:Name="camera"></PerspectiveCamera>-->
            <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>
                                    <DiffuseMaterial.Brush>
                                        <VisualBrush>
                                            <VisualBrush.Visual>
                                                <Image Source="cubesurface.jpg">
                                                    <Image.Style>
                                                        <Style>
                                                            <Setter Property="Image.Opacity" Value="0.6"></Setter>
                                                        </Style>
                                                    </Image.Style>
                                                </Image>
                                            </VisualBrush.Visual>
                                        </VisualBrush>
                                    </DiffuseMaterial.Brush>
                                </DiffuseMaterial>-->
                                <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实体。

演示程序 源代码

目录
相关文章
|
16天前
|
C#
WPF —— 动画缩放变换
`ScaleTransform`用于二维x-y坐标系中对象的缩放,可沿X或Y轴调整。在故事板中,通过RenderTransform.ScaleX和ScaleY属性控制缩放。示例代码展示了如何设置按钮的RenderTransformOrigin、Background等属性,并通过LayoutTransform应用ScaleTransform。当鼠标进入按钮时,EventTrigger启动DoubleAnimation实现X和Y轴的缩放动画。最后,展示了如何将动画集成到自定义按钮样式中。
12 0
|
C# Windows 图形学
优化WPF 3D性能
原文:优化WPF 3D性能 Maximize WPF 3D Performance .NET Framework 4.5   As you use the Windows Presentation Foundation (WPF) to build 3D contr...
1316 0
|
C#
WPF和Expression Blend开发实例:Adorner(装饰器)应用实例
原文:WPF和Expression Blend开发实例:Adorner(装饰器)应用实例 装饰器-- 表示用于修饰 UIElement 的 FrameworkElement 的抽象类 简单来说就是,在不改变一个UIElement结构的情况下,将一个Visual对象加到它上面.
991 0
|
C#
WPF特效-实现3D足球效果
原文:WPF特效-实现3D足球效果 WPF 实现 3D足球效果,效果图如下:  每个面加载不同贴图。                                                          ...
860 0
|
C#
WPF DispatcherTimer(定时器应用) 无人触摸60s自动关闭窗口
原文:WPF DispatcherTimer(定时器应用) 无人触摸60s自动关闭窗口 如果无人触摸:60s自动关闭窗口 xmal:部分             OK        你好!    cs:部分 //60s无人操作自动关闭        DispatcherTimer dTi...
1537 0
|
C# 索引 容器
WPF ListView控件设置奇偶行背景色交替变换以及ListViewItem鼠标悬停动画
原文:WPF ListView控件设置奇偶行背景色交替变换以及ListViewItem鼠标悬停动画 利用WPF的ListView控件实现类似于Winform中DataGrid行背景色交替变换的效果,同时增加鼠标的悬停效果。
1733 0
|
C#
【C#/WPF】Image图片的Transform变换:平移、缩放、旋转
原文:【C#/WPF】Image图片的Transform变换:平移、缩放、旋转 WPF中图像控件Image的变换属性Transform: 平移 缩放 旋转 即要想实现图片的平移、缩放、旋转,是修改它所在的Image控件的Transform变换属性。
4737 0
|
C#
WPF线性渐变画刷应用之——炫彩线条
原文:WPF线性渐变画刷应用之——炫彩线条 效果图: Xaml代码:                                                          
917 0
|
C#
在WPF中将图片转换成3D图像并可以旋转
原文:在WPF中将图片转换成3D图像并可以旋转 时光偷走的,永远都是我们眼皮底下看不见的珍贵。   https://pan.baidu.com/s/14dk-OU2SR0nxXj2bL4bVpQ 首先先看一下源代码最初的运行效果,是否是自己需要的。
1486 0
|
C# API
WPF关闭应用汇总
原文:WPF关闭应用汇总 就本人而言,C#中关闭应用主要有以下途径: 1.Close():关闭当前窗口,可以在OnClosing和 OnClosed中捕获消息,在OnClosing的时候,可以取消关闭窗口 2.
1139 0