WPF 3D开发实例和hedix应用

1 篇文章 0 订阅
1 篇文章 0 订阅

3D开发基础知识

坐标系 Coodinate System

WPF中二维图形的坐标系将原点定位在呈现区域(通常是屏幕)的左上角。 在二维系统中,x 轴上的正值朝右,y 轴上的正值朝下。而在三维坐标系中,原点位于呈现区域的中心,x 轴上的正值朝右,但是 y 轴上的正值朝上,z 轴上的正值从原点向外朝向观察者。传统的二维和三维坐标系表示形式如下图
coordinate system

由这些轴定义的空间是三维对象在 WPF 中的固定参考框架。
当您在该空间中生成模型并创建光源和照相机以查看这些模型时,一定要在向每个模型应用变换时,将固定参考框架或“全局空间”与您为该模型创建的局部参考框架区分开。

另请记住,根据光源和照相机设置,全局空间中的对象可能会看上去完全不同或者根本不可见,但是照相机的位置不会改变对象在全局空间中的位置。

3D的世界都是三角形的王国

3D Model

在3D的世界里所有的东西都是用一些列的“三角形”来描述的。那你一定会问为什么是“三角形”?
原因是三角形是用来描述一个平面的最细微的几何体,渲染引擎能够依据每个三角形的材质以及场景中的灯光角度来计算它的颜色。
其实就是三点确定一个平面,在一个平面上做计算最简单,考虑的因素最少。如果用三维空间中大于三个点来做渲染基本单位,那么如果这些点不在同一个平面上的话,渲染计算是相当复杂的。

3D 对象的表面叫做网格(Mesh),一个网格是由许多3D 点来定义的,这些点叫做顶点(vertices)。这些顶点通过缠绕模式(winding pattern)连接在一起组成一个一个的三角形(facet)(如下图箭头所示)。
在这里插入图片描述
三角形(facet/triangle)又分为“前”和“后”两面,能看到的部分为前面,看不到的部分为后面。

那怎么判定是前面还是后面?

如果三角形的三个点顺时针方向组成的面那么这个面就是前面。如下图

在这里插入图片描述
按照0,1,2的顺序三个点组成了的这个面是上面我们可以看到

实际上是因为正面和反面的法向量(垂直于平面)与是向量的夹角,夹角小于90 说明是正面可以看见,反之是反面。

目前主流(Direct3D and/or OpenGL)都会把三角形分为两个面(前面和后面)。

为帮助大家记忆(facet)“前面”的三维坐标,大拇指是Z+的方向正对着我们(及前面图示中Up方向),食指是y+方向,而中指是Y+方向。(+表示正数的方向)
在这里插入图片描述

WPF 3D的关键元素(Elements)

在这里插入图片描述

要画画总的有个画布,WPF中呈现3D也需要一个类似功能的东西。Viewport3D(投影3D场景的平面)是WPF中的3D画布,类于2D中的Canvas。其实WPF中也有一个名字看起来类似的东东Viewbox ,不过和3D没啥关系,它处理的都是2D的。

<Viewport3D>
Children…
</Viewport3D>

该图形系统将 Viewport3D 视为一个像 WPF 中的许多其他元素一样的二维可视化元素。
Viewport3D充当三维场景中的窗口(即视区)。 更准确地说,它是三维场景所投影到的图面。

相机(Camera)

处理二维对象的开发人员习惯于将绘图基元置于二维屏幕上。 当您创建三维场景时,一定要记住您实际上是要创建三维对象的二维表示形式。 由于三维场景的外观会因观察者的观察位置不同而异,因此您必须指定观察位置。而观察位置就是由相机(Camera 类)来为三维场景指定的。

另一种理解三维场景在二维图上的描述方法就是,将3D场景投影到一个2D平面的表面。如下图:
在这里插入图片描述
从坐标系的角度来看下我们的ProjectionCamera(透视相机)和3D模型的位置,以及2D 投影屏幕的位置关系:

在这里插入图片描述
更详细的图解如下:
在这里插入图片描述

ProjectionCamera 的 NearPlaneDistance 和 FarPlaneDistance
属性限制照相机的投影范围。由于照相机可以位于场景中的任何位置,因此照相机实际上可能会位于模型内部或者紧靠模型,这使正确区分对象变得很困难。
通过 NearPlaneDistance,可以指定一个距离照相机的最小距离,超过该距离后即不绘制对象。 相反,使用
FarPlaneDistance,可以指定一个距离照相机的距离(即,在超过该距离后将不绘制对象),从而确保因距离太远而无法识别的对象将不包括在场景中。

对比WPF中两种相机

PerspectiveCamera 可以指定不同的投影及其属性以更改观察者查看三维模型的方式。
OrthographicCamera 指定三维模型到二维可视化图面上的正投影与其他照相机一样,它指定位置、观察方向和“向上”方向。 但是,与 PerspectiveCamera 不同的是,OrthographicCamera 描述了不包括透视收缩的投影。或者说OrthographicCamera 描述了一个侧面平行的取景框,而不是侧面汇集在场景中一点的取景框。
下图演示使用PerspectiveCamera 和 OrthographicCamera 查看同一模型时的不同效果。

在这里插入图片描述

灯光

和现实生活中一样,如果没有光我们将什么也看不到。因此我们需要在我们的场景中至少放置一盏灯来照亮我们场景中的模型。

WPF中支持不同类型的光源,如下:

  • AmbientLight(环境光) 它所提供的环境光会照亮所有的对象,而不考虑对象的位置或方向。
  • DirectionalLight(平行光) 像远处的光源那样照亮(如太阳光)。将方向光的 Direction 指定为 Vector3D,但是没有为方向光指定位置。
  • PointLight(点光源) 像近处的光源那样照亮。 PointLight 具有一个位置并从该位置投射光。 场景中的对象是根据对象相对于光源的位置和距离而被照亮的。 PointLightBase 公开 Range 属性,该属性确定一个距离,超过该距离后模型将无法由光源照亮。 PointLight 还公开了多个衰减属性,这些属性确定光源的亮度如何随距离的增加而减小。 您可以为光源的衰减指定恒定、线性或二次内插算法。
  • SpotLight(聚光灯) 从 PointLight 继承。 Spotlight 的照亮方式与 PointLight 类似,但是它既具有位置又具有方向。 它们在 InnerConeAngle 和 OuterConeAngle 属性所设置的锥形区域(以度为单位指定)中投射光。

下图展示了各种光源的情况:
在这里插入图片描述

光源是 Model3D 对象,因此您可以转换光源对象并对光源属性(包括位置、颜色、方向和范围)进行动画处理。

组合灯光的效果

  • Ambient color : Red
  • Difusse color : Red

在这里插入图片描述

3D模型

说了半天啦,怎么主角还没出现了 ??

对,所有的一切都服务于我们的3D Model。
在这里插入图片描述
Model3D 是三维对象的抽象基类。若要生成三维场景,需要一些要查看的对象,而且构成场景图的对象必须派生自 Model3D。 目前,WPF 支持用 GeometryModel3D 对几何形状进行建模。 此模型的 Geometry 属性采用网格基元。

要生成模型,首先生成一个基元或网格。 三维基元是一系列构成单个三维实体的顶点。 大多数三维系统都提供在最简单的闭合图(由三个顶点定义的三角形)上建模的基元。 由于三角形的三个点在一个平面上,因此您可以继续添加三角形,以便对网格这样较为复杂的形状建模。

WPF 三维系统目前提供 MeshGeometry3D 类,使用该类可以指定任何几何形状;它目前不支持预定义的三维基元(如球体和立方体)。 首先通过将三角形顶点的列表指定为它的Positions 属性来创建 MeshGeometry3D。 每个顶点都指定为 Point3D。 (在可扩展应用程序标记语言 (XAML) 中,将该属性指定为三个一组的数字列表,每组中的三个数字表示每个顶点的坐标)。根据网格的几何形状,网格可能会由多个三角形组成,其中的一些三角形共用相同的角(顶点)。 若要正确地绘制网格,WPF 需要有关哪些顶点由哪些三角形共用的信息。 可以通过指定具有 TriangleIndices 属性的三角形索引列表来提供此信息。 此列表指定在 Positions 列表中指定的点将按哪种顺序确定三角形。

材质(Material)

我们生活在多彩的世界中,也不能让我们的3D模型如此单调,这时我们就用到了材质。
在这里插入图片描述
在二维中,可以使用 Brush 类来向屏幕中的区域应用颜色、图案、渐变或其他可视化内容。 但是,三维对象的外观是照明模型的功能,而不只是应用于它们的颜色或图案。 实际对象的图面质量不同,它们反射光的方式也会有所不同:光亮的图面与粗糙或不光滑的图面看上去不同,某些对象似乎可以吸收光,而某些对象似乎能够发光。 您可以向三维对象应用与应用于二维对象的完全相同的画笔,但是您不能直接应用它们。

Material 的具体子类用来确定模型图面的某些外观特征,每个子类还提供一个可以向其传递 SolidColorBrush、TileBrush 或 VisualBrush 的 Brush 属性。

  • DiffuseMaterial 使用 DiffuseMaterial 与直接针对二维模型使用画笔非常相似;模型表面不反射光,就好像是自发光一样。使用 DiffuseMaterial 与直接针对二维模型使用画笔非常相似;模型表面不反射光,就好像是自发光一样
  • SpecularMaterial 可以通过为 SpecularPower 属性指定一个值来设置系统将为纹理的反射特质(或“发光”)建议的度数。
  • EmissiveMaterial 可以指定将应用纹理,就好像模型所发出的光与画笔的颜色相同。这不会使模型成为光源;但是,它参与阴影设置的方式将不同于用 DiffuseMaterial 或 SpecularMaterial 设置纹理时的情况。
    在这里插入图片描述

为进一步提高性能,可以从场景中精选 GeometryModel3D 的背面(由于它们相对于照相机位于模型的背面,因此您将看不到这些面)。若要指定要应用于模型(如飞机)背面的Material,请设置模型的 BackMaterial 属性。

为了实现某些图面质量(如发光或发射效果),您可能希望向模型连续应用几个不同的画笔。 可以使用 MaterialGroup 类来应用和重用多个 Material。 MaterialGroup 的子级在多个呈现过程中按照从头到尾的顺序来应用。

WPF 中的3D变换

在这里插入图片描述

当您创建模型时,它们在场景中具有固定的位置。为了在场景中移动、旋转这些模型或者更改这些模型的大小而更改用来定义模型本身的顶点是不切实际的。 相反,您可以像在二维模型一样应用转换。

每个模型对象都有一个可用来对模型进行移动、重定向或调整大小的 Transform 属性。 当您应用转换时,实际上是按照由Transform 属性指定的向量或值来偏移模型的所有点。

动画

WPF 三维实现与二维图形参与同一个计时和动画系统。也就是说,要对三维场景进行动画处理,也就是对其模型的属性进行动画处理。 可以直接对基元的属性进行动画处理,但是通常很容易更改模型位置或外观的变换进行动画处理。 由于可以向 Model3DGroup 对象及其各个模型应用转换,因此可以向 Model3DGroup 中某个对象应用一组动画,也可以向这一组子对象应用一组动画。 还可以通过对场景的照明属性进行动画处理来实现各种可视化效果。 最后,您可以选择通过对照相机的位置或视野进行动画处理来对投影本身进行动画处理。

要对 WPF 中的对象进行动画处理,可以创建时间线、定义动画(实际上是随着时间的推移而更改某个属性值)并指定要向其应用动画的属性。
由于三维场景中的所有对象都是Viewport3D 的子节点,因此要应用于场景的任何动画所面向的属性都是 Viewport3D 的属性。

常用辅助类

  1. HelixToolkit
  2. 3DTool
  3. slimdx

由于WPF 3D 是基于Direct 3D,和WPF 2D一样直接利用显卡渲染的,并且默认开启了全景反锯齿(有个条件,需要你的显卡支持> 兼容WDDM-Compliant)

实例

  <Viewport3D Name="myViewport" >

    <!-- Add a camera. -->
    <Viewport3D.Camera>
      <PerspectiveCamera
                    FarPlaneDistance="20" 
                    LookDirection="0,0,1" 
                    UpDirection="0,1,0" 
                    NearPlaneDistance="1" 
                    Position="0,0,-3" 
                    FieldOfView="45" />
    </Viewport3D.Camera>

    <!-- Add models. -->
    <Viewport3D.Children>

      <ModelVisual3D>
        <ModelVisual3D.Content>

          <Model3DGroup >
            <Model3DGroup.Children>

              <!-- Lights, MeshGeometry3D and DiffuseMaterial objects are added to the ModelVisual3D. -->
              <DirectionalLight Color="#FFFFFFFF" Direction="3,-4,5" />

              <!-- Define a red cone. -->
              <GeometryModel3D>

                <GeometryModel3D.Geometry>
                  <MeshGeometry3D
Positions="0.293893 -0.5 0.404509  0.475528 -0.5 0.154509  0 0.5 0  0.475528 -0.5 0.154509  0 0.5 0  0 0.5 0  0.475528 -0.5 0.154509  0.475528 -0.5 -0.154509  0 0.5 0  0.475528 -0.5 -0.154509  0 0.5 0  0 0.5 0  0.475528 -0.5 -0.154509  0.293893 -0.5 -0.404509  0 0.5 0  0.293893 -0.5 -0.404509  0 0.5 0  0 0.5 0  0.293893 -0.5 -0.404509  0 -0.5 -0.5  0 0.5 0  0 -0.5 -0.5  0 0.5 0  0 0.5 0  0 -0.5 -0.5  -0.293893 -0.5 -0.404509  0 0.5 0  -0.293893 -0.5 -0.404509  0 0.5 0  0 0.5 0  -0.293893 -0.5 -0.404509  -0.475528 -0.5 -0.154509  0 0.5 0  -0.475528 -0.5 -0.154509  0 0.5 0  0 0.5 0  -0.475528 -0.5 -0.154509  -0.475528 -0.5 0.154509  0 0.5 0  -0.475528 -0.5 0.154509  0 0.5 0  0 0.5 0  -0.475528 -0.5 0.154509  -0.293892 -0.5 0.404509  0 0.5 0  -0.293892 -0.5 0.404509  0 0.5 0  0 0.5 0  -0.293892 -0.5 0.404509  0 -0.5 0.5  0 0.5 0  0 -0.5 0.5  0 0.5 0  0 0.5 0  0 -0.5 0.5  0.293893 -0.5 0.404509  0 0.5 0  0.293893 -0.5 0.404509  0 0.5 0  0 0.5 0  " 
Normals="0.7236065,0.4472139,0.5257313  0.2763934,0.4472138,0.8506507  0.5308242,0.4294462,0.7306172  0.2763934,0.4472138,0.8506507  0,0.4294458,0.9030925  0.5308242,0.4294462,0.7306172  0.2763934,0.4472138,0.8506507  -0.2763934,0.4472138,0.8506507  0,0.4294458,0.9030925  -0.2763934,0.4472138,0.8506507  -0.5308242,0.4294462,0.7306172  0,0.4294458,0.9030925  -0.2763934,0.4472138,0.8506507  -0.7236065,0.4472139,0.5257313  -0.5308242,0.4294462,0.7306172  -0.7236065,0.4472139,0.5257313  -0.858892,0.429446,0.279071  -0.5308242,0.4294462,0.7306172  -0.7236065,0.4472139,0.5257313  -0.8944269,0.4472139,0  -0.858892,0.429446,0.279071  -0.8944269,0.4472139,0  -0.858892,0.429446,-0.279071  -0.858892,0.429446,0.279071  -0.8944269,0.4472139,0  -0.7236065,0.4472139,-0.5257313  -0.858892,0.429446,-0.279071  -0.7236065,0.4472139,-0.5257313  -0.5308242,0.4294462,-0.7306172  -0.858892,0.429446,-0.279071  -0.7236065,0.4472139,-0.5257313  -0.2763934,0.4472138,-0.8506507  -0.5308242,0.4294462,-0.7306172  -0.2763934,0.4472138,-0.8506507  0,0.4294458,-0.9030925  -0.5308242,0.4294462,-0.7306172  -0.2763934,0.4472138,-0.8506507  0.2763934,0.4472138,-0.8506507  0,0.4294458,-0.9030925  0.2763934,0.4472138,-0.8506507  0.5308249,0.4294459,-0.7306169  0,0.4294458,-0.9030925  0.2763934,0.4472138,-0.8506507  0.7236068,0.4472141,-0.5257306  0.5308249,0.4294459,-0.7306169  0.7236068,0.4472141,-0.5257306  0.8588922,0.4294461,-0.27907  0.5308249,0.4294459,-0.7306169  0.7236068,0.4472141,-0.5257306  0.8944269,0.4472139,0  0.8588922,0.4294461,-0.27907  0.8944269,0.4472139,0  0.858892,0.429446,0.279071  0.8588922,0.4294461,-0.27907  0.8944269,0.4472139,0  0.7236065,0.4472139,0.5257313  0.858892,0.429446,0.279071  0.7236065,0.4472139,0.5257313  0.5308242,0.4294462,0.7306172  0.858892,0.429446,0.279071  "                   TriangleIndices="0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 " />
                </GeometryModel3D.Geometry>

                <GeometryModel3D.Material>
                  <DiffuseMaterial>
                    <DiffuseMaterial.Brush>
                      <SolidColorBrush
                        Color="Red" 
                        Opacity="1.0"/>
                    </DiffuseMaterial.Brush>
                  </DiffuseMaterial>
                </GeometryModel3D.Material>

              </GeometryModel3D>

            </Model3DGroup.Children>
          </Model3DGroup>

        </ModelVisual3D.Content>

      </ModelVisual3D>

    </Viewport3D.Children>

  </Viewport3D>

WPF利用HelixToolKit后台导入3D模型

WPF利用HelixToolKit后台导入3D模型
1.新建一个WPF项目,引用–》管理nuGet程序包–》联机–》搜索helixtoolkit–》安装
在这里插入图片描述
2.xaml文件中引入 xmlns:helix=”http://helix-toolkit.org/wpf”

<Window x:Class="Import3D.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        **xmlns:helix="http://helix-toolkit.org/wpf"***强调内容*
        Title="MainWindow" WindowState="Maximized">
  <helix:HelixViewport3D >
  <!--相机位置也很重要,位置不对,看到的模型就很奇怪-->
            <helix:HelixViewport3D.Camera>
                <PerspectiveCamera FieldOfView="45" FarPlaneDistance="1098.9153169227836" LookDirection="0,0,-414.387754871885" NearPlaneDistance="0.1" Position="9.9475983006414E-14,91.037123633789,414.387754871885" UpDirection="0,1,0"/>
            </helix:HelixViewport3D.Camera>
             <!--很重要,没有灯光场景是黑的-->
            <helix:DefaultLights></helix:DefaultLights>   
            <ModelVisual3D x:Name="model"></ModelVisual3D>

        </helix:HelixViewport3D>

3.cs代码:导入obj 3d文件

  public MainWindow()
        {
            InitializeComponent();
            ObjReader CurrentHelixObjReader = new ObjReader();
              //相对路径,新建了一个objFile文件夹,添加了mtl,obj 和纹理图片
            Model3DGroup MyModel = CurrentHelixObjReader.Read(@".\objFile\ez.obj");
           // Model3DGroup MyModel = CurrentHelixObjReader.Read(@"C:\Users\Administrator\Desktop\simplexaml\simplexaml\bridgesimple712r.obj");

            // Display the model
            model.Content = MyModel;
        }

4.如果模型出不来,尝试修改mtl,obj,纹理图片的属性
复制到输出目录:始终复制
生成操作:内容

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
基于WPF3D开发是一种用于创建交互式和具有视觉效果的应用程序的技术。在WPF(Windows Presentation Foundation)中,开发人员可以使用内置的3D功能来创建复杂的3D场景和对象。 要开始基于WPF3D开发,您首先需要了解基本的WPF概念和语法。这包括了解如何创建XAML(可扩展应用程序标记语言)文件和使用WPF的命名空间和控件。您还需要熟悉C#编程语言,因为WPF使用C#作为主要的开发语言。 接下来,您可以开始使用WPF3D功能。WPF提供了一些基本的3D对象,如Cube、Sphere和Cylinder等。您可以使用这些对象创建简单的3D场景。您还可以使用材质和光源来增强这些对象的视觉效果。 除了基本的3D对象,WPF还提供了一些功能强大的3D控件,如Viewport3D和ModelVisual3D等。这些控件可以帮助您创建更复杂的3D场景和对象。您可以在这些控件中添加网格、模型和纹理等来创建更真实的3D效果。 在开发过程中,您可能需要了解一些3D数学和几何概念,如坐标系、投影和变换等。这些概念将帮助您理解和操作3D对象。 最后,当您完成基于WPF3D应用程序开发时,您可以将其部署到Windows平台上的任何设备上。WPF提供了高度可定制和可伸缩的界面,使您的应用程序可以适应不同的屏幕尺寸和分辨率。 综上所述,基于WPF3D开发是一种逐渐成熟和广泛采用的技术,可以帮助您创建具有丰富视觉效果的应用程序。通过学习WPF的基本概念和语法,以及一些3D数学和几何概念,您可以快速入门并创建出令人印象深刻的3D应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值