三维图形概述

Windows Presentation Foundation (WPF) 中的 3D 功能使开发人员能够在标记和程序代码中绘制、转换和动画化 3D 图形。 开发人员可以合并 2D 和 3D 图形以创建丰富的控件、提供复杂的数据图解,或者增强用户对应用程序界面的体验。 WPF 中的 3D 支持并非旨在提供功能齐全的游戏开发平台。 本主题概述了 WPF 图形系统中的 3D 功能。

2D 容器中的 3D

WPF 中的 3D 图形内容封装在 Viewport3D 元素中,该元素可以参与二维元素结构。 该图形系统将 Viewport3D 视为一个二维视觉元素,就像 WPF 中的许多其他元素一样。 Viewport3D 充当三维场景中的窗口(即视区)。 更准确地说,它是 3D 场景所投影到的图面。

在传统的 2D 应用程序中,当需要使用 Grid 或 Canvas 之类的另一个容器元素时,可以使用 Viewport3D。 尽管可以在同一个场景图中将 Viewport3D 与其他 2D 绘图对象一起使用,但不能在 Viewport3D 中相互渗透 2D 和 3D 对象。 本主题重点讲述如何在 Viewport3D 内部绘制 3D 图形。

3D 坐标空间

2D 图形的 WPF 坐标系将原点定位在呈现区域(通常是屏幕)的左上角。 在 2D 系统中,x 轴上的正值朝右,y 轴上的正值朝下。 但是,在 3D 坐标系中,原点位于呈现区域的中心,x 轴上的正值朝右,但是 y 轴上的正值朝上,z 轴上的正值从原点向外朝向观察者。

Coordinate systems
传统的 2D 和 3D 坐标系表示形式

由这些轴定义的空间是 3D 对象在 WPF 中的固定参考框架。 当在该空间中生成模型并创建光源和照相机以查看这些模型时,一定要在向每个模型应用转换时,将固定参考框架或“全局空间”与为该模型创建的局部参考框架区分开。 另请记住,根据光源和照相机设置,全局空间中的对象可能会看上去完全不同或者根本不可见,但是照相机的位置不会改变对象在全局空间中的位置。

照相机和投影

处理 2D 的开发人员习惯于将绘图基元置于二维屏幕上。 创建 3D 场景时,务必记住实际上是要创建 3D 对象的 2D 表示形式。 由于 3D 场景的外观会因观察者的观察位置而异,因此必须指定观察位置。 可以使用 Camera 类来为 3D 场景指定观察位置。

了解 3D 场景如何在 2D 图面上表示的另一种方法就是将场景描述为到观察图面上的投影。 使用 ProjectionCamera,可以指定不同的投影及其属性,以更改观察者查看 3D 模型的方式。 PerspectiveCamera 指定用来对场景进行透视收缩的投影。 换言之,PerspectiveCamera 提供消失点透视。 可以指定照相机在场景坐标系中的位置、照相机的方向和视野以及用来定义场景中“向上”方向的矢量。 下图阐释了 PerspectiveCamera 的投影。

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

Camera setup
照相机位置

OrthographicCamera 指定 3D 模型到 2D 可视图面上的正投影。 与其他照相机一样,它指定位置、观察方向和“向上”方向。 但是,与 PerspectiveCamera 不同的是,OrthographicCamera 描述了不包括透视收缩的投影。 换言之,OrthographicCamera 描述了一个侧面平行的取景框,而不是侧面汇集在照相机中一点的取景框。 下图演示使用 PerspectiveCameraOrthographicCamera 查看同一模型时的情况。

Orthographic and perspective projection
透视投影和正投影

下面的代码演示一些典型的照相机设置。

// Defines the camera used to view the 3D object. In order to view the 3D object,
// the camera must be positioned and pointed such that the object is within view
// of the camera.
PerspectiveCamera myPCamera = new PerspectiveCamera();

// Specify where in the 3D scene the camera is.
myPCamera.Position = new Point3D(0, 0, 2);

// Specify the direction that the camera is pointing.
myPCamera.LookDirection = new Vector3D(0, 0, -1);

// Define camera's horizontal field of view in degrees.
myPCamera.FieldOfView = 60;

// Asign the camera to the viewport
myViewport3D.Camera = myPCamera;
' Defines the camera used to view the 3D object. In order to view the 3D object,
' the camera must be positioned and pointed such that the object is within view 
' of the camera.
Dim myPCamera As New PerspectiveCamera()

' Specify where in the 3D scene the camera is.
myPCamera.Position = New Point3D(0, 0, 2)

' Specify the direction that the camera is pointing.
myPCamera.LookDirection = New Vector3D(0, 0, -1)

' Define camera's horizontal field of view in degrees.
myPCamera.FieldOfView = 60

' Asign the camera to the viewport
myViewport3D.Camera = myPCamera

模型和网格基元

Model3D 是表示泛型 3D 对象的抽象基类。 若要生成 3D 场景,需要一些要查看的对象,而且构成场景图的对象必须派生自 Model3D。 目前,WPF 支持用 GeometryModel3D 对几何图形进行建模。 此模型的 Geometry 属性采用网格基元。

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

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

<GeometryModel3D>
  <GeometryModel3D.Geometry>
          <MeshGeometry3D 
              Positions="-1 -1 0  1 -1 0  -1 1 0  1 1 0"
              Normals="0 0 1  0 0 1  0 0 1  0 0 1"
              TextureCoordinates="0 1  1 1  0 0  1 0   "
              TriangleIndices="0 1 2  1 3 2" />
      </GeometryModel3D.Geometry>
      <GeometryModel3D.Material>
          <DiffuseMaterial>
              <DiffuseMaterial.Brush>
                  <SolidColorBrush Color="Cyan" Opacity="0.3"/>
              </DiffuseMaterial.Brush>
          </DiffuseMaterial>
      </GeometryModel3D.Material>
  <!-- Translate the plane. -->
      <GeometryModel3D.Transform>
          <TranslateTransform3D
            OffsetX="2" OffsetY="0" OffsetZ="-1"   >
          </TranslateTransform3D>
      </GeometryModel3D.Transform>
  </GeometryModel3D>

在上面的示例中,Positions列表指定四个顶点以定义矩形网格。 TriangleIndices属性指定了包含两个组的列表,每组由三个索引组成。 列表中的每个数字指的是 Positions 列表中的偏移量。 例如,由Positions列表指定的第一组三个顶点为 (-1,-1,0)、(1,-1,0) 和 (-1,1,0)。 由TriangleIndices列表指定的第一组三个索引为 0、1 和 2,这与Positions列表中的第一个、第二个和第三个点相对应。 因此,构成立方体模型的第一个矩形将按照从 (-1,-1,0) 到 (1,-1,0) 再到 (-1,1,0) 的顺序组合而成,第二个三角形将按照类似方式确定。

可以通过为 NormalsTextureCoordinates 属性指定值来继续定义模型。 为了呈现模型的图面,图形系统需要有关曲面在任何给定三角形上的朝向信息。 图形系统使用此信息来针对该模型进行照明计算:正对光源的图面比偏离光源的图面显得更亮。 尽管 WPF 可以使用位置坐标来确定默认的法矢量,但是你还可以指定不同的法矢量来近似计算曲面的外观。

TextureCoordinates 属性指定 Point 的集合,用于通知图形系统如何将确定纹理绘制方式的坐标映射到网格的顶点。 TextureCoordinates 指定为 0 和 1 之间(包含这两个值)的值。 与 Normals 属性一样,图形系统可以计算默认纹理坐标,但你可以选择设置不同的纹理坐标来控制包括部分重复图案的纹理的映射。 有关纹理坐标的详细信息,可在后续主题或 Managed Direct3D SDK 中找到。

下面的示例演示如何在过程代码中创建立方体模型的一面。 可以将整个立方体绘制为单个GeometryModel3D;此示例将该立方体面绘制为一个不同的模型,以便在以后向每个面应用不同的纹理。

MeshGeometry3D side1Plane = new MeshGeometry3D();
Private side1Plane As New MeshGeometry3D()
side1Plane.Positions.Add(new Point3D(-0.5, -0.5, -0.5));
side1Plane.Positions.Add(new Point3D(-0.5, 0.5, -0.5));
side1Plane.Positions.Add(new Point3D(0.5, 0.5, -0.5));
side1Plane.Positions.Add(new Point3D(0.5, 0.5, -0.5));
side1Plane.Positions.Add(new Point3D(0.5, -0.5, -0.5));
side1Plane.Positions.Add(new Point3D(-0.5, -0.5, -0.5));

side1Plane.TriangleIndices.Add(0);
side1Plane.TriangleIndices.Add(1);
side1Plane.TriangleIndices.Add(2);
side1Plane.TriangleIndices.Add(3);
side1Plane.TriangleIndices.Add(4);
side1Plane.TriangleIndices.Add(5);

side1Plane.Normals.Add(new Vector3D(0, 0, -1));
side1Plane.Normals.Add(new Vector3D(0, 0, -1));
side1Plane.Normals.Add(new Vector3D(0, 0, -1));
side1Plane.Normals.Add(new Vector3D(0, 0, -1));
side1Plane.Normals.Add(new Vector3D(0, 0, -1));
side1Plane.Normals.Add(new Vector3D(0, 0, -1));

side1Plane.TextureCoordinates.Add(new Point(1, 0));
side1Plane.TextureCoordinates.Add(new Point(1, 1));
side1Plane.TextureCoordinates.Add(new Point(0, 1));
side1Plane.TextureCoordinates.Add(new Point(0, 1));
side1Plane.TextureCoordinates.Add(new Point(0, 0));
side1Plane.TextureCoordinates.Add(new Point(1, 0));
side1Plane.Positions.Add(New Point3D(-0.5, -0.5, -0.5))
side1Plane.Positions.Add(New Point3D(-0.5, 0.5, -0.5))
side1Plane.Positions.Add(New Point3D(0.5, 0.5, -0.5))
side1Plane.Positions.Add(New Point3D(0.5, 0.5, -0.5))
side1Plane.Positions.Add(New Point3D(0.5, -0.5, -0.5))
side1Plane.Positions.Add(New Point3D(-0.5, -0.5, -0.5))

side1Plane.TriangleIndices.Add(0)
side1Plane.TriangleIndices.Add(1)
side1Plane.TriangleIndices.Add(2)
side1Plane.TriangleIndices.Add(3)
side1Plane.TriangleIndices.Add(4)
side1Plane.TriangleIndices.Add(5)

side1Plane.Normals.Add(New Vector3D(0, 0, -1))
side1Plane.Normals.Add(New Vector3D(0, 0, -1))
side1Plane.Normals.Add(New Vector3D(0, 0, -1))
side1Plane.Normals.Add(New Vector3D(0, 0, -1))
side1Plane.Normals.Add(New Vector3D(0, 0, -1))
side1Plane.Normals.Add(New Vector3D(0, 0, -1))

side1Plane.TextureCoordinates.Add(New Point(1, 0))
side1Plane.TextureCoordinates.Add(New Point(1, 1))
side1Plane.TextureCoordinates.Add(New Point(0, 1))
side1Plane.TextureCoordinates.Add(New Point(0, 1))
side1Plane.TextureCoordinates.Add(New Point(0, 0))
side1Plane.TextureCoordinates.Add(New Point(1, 0))

'

向模型应用材料

为了使网格看上去像三维对象,必须向其应用纹理,以便覆盖由顶点和三角形定义的图面,从而使其可以由照相机照明和投影。 在 2D 中,可以使用 Brush 类向屏幕中的区域应用颜色、图案、渐变或其他视觉内容。 但是,3D 对象的外观取决于照明模型,而不仅仅是应用于它们的颜色或图案。 实际对象的图面质量不同,它们反射光的方式也会有所不同:光亮的图面与粗糙或不光滑的图面看上去不同,某些对象似乎可以吸收光,而某些对象似乎能够发光。 可以向 3D 对象应用与 2D 对象完全相同的画笔,但是不能直接应用它们。

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

  • DiffuseMaterial 指定将向模型应用画笔,就好像模型是使用漫射光来照亮的一样。 使用 DiffuseMaterial 与直接针对 2D 模型使用画笔非常相似;模型图面不反射光,就好像是自发光一样。

  • SpecularMaterial 指定将向模型应用画笔,就好像模型的表面坚硬或者光亮,能够反射光一样。 可以通过为 SpecularPower 属性指定一个值,来设置系统将为纹理的反射特质(或“发光”)建议的度数。

  • 使用 EmissiveMaterial 可以指定将应用纹理,就好像模型所发出的光与画笔的颜色相同。 这不会使模型成为光源;但是它参与阴影设置的方式将不同于用 DiffuseMaterial 或 SpecularMaterial 设置纹理时的情况。

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

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

以下代码示例演示如何将纯色和绘图以画笔形式应用于 3D 模型。

<GeometryModel3D.Material>
    <DiffuseMaterial>
        <DiffuseMaterial.Brush>
            <SolidColorBrush Color="Cyan" Opacity="0.3"/>
        </DiffuseMaterial.Brush>
    </DiffuseMaterial>
</GeometryModel3D.Material>
<DrawingBrush x:Key="patternBrush" Viewport="0,0,0.1,0.1" TileMode="Tile">
  <DrawingBrush.Drawing>
    <DrawingGroup>
      <DrawingGroup.Children>
        <GeometryDrawing Geometry="M0,0.1 L0.1,0 1,0.9, 0.9,1z"
          Brush="Gray" />
        <GeometryDrawing Geometry="M0.9,0 L1,0.1 0.1,1 0,0.9z"
          Brush="Gray" />
        <GeometryDrawing Geometry="M0.25,0.25 L0.5,0.125 0.75,0.25 0.5,0.5z"
          Brush="#FFFF00" />
        <GeometryDrawing Geometry="M0.25,0.75 L0.5,0.875 0.75,0.75 0.5,0.5z"
          Brush="Black" />
        <GeometryDrawing Geometry="M0.25,0.75 L0.125,0.5 0.25,0.25 0.5,0.5z"
          Brush="#FF0000" />
        <GeometryDrawing Geometry="M0.75,0.25 L0.875,0.5 0.75,0.75 0.5,0.5z"
          Brush="MediumBlue" />
      </DrawingGroup.Children>
    </DrawingGroup>
  </DrawingBrush.Drawing>
</DrawingBrush>
DiffuseMaterial side5Material = new DiffuseMaterial((Brush)Application.Current.Resources["patternBrush"]);
Dim side5Material As New DiffuseMaterial(CType(Application.Current.Resources("patternBrush"), Brush))

照亮场景

与实际的光一样,3D 图形中的光能够使图面可见。 更确切地说,光确定了场景的哪个部分将包括在投影中。 WPF 中的光对象创建了各种光和阴影效果,并且按照各种实际光的行为进行了建模。 至少在场景中包括一个光源,否则模型将不可见。

下面的光源派生自基类 Light

  • AmbientLight:它所提供的环境光以一致的方式照亮所有对象,这与对象的位置或方向无关。

  • DirectionalLight:像远处的光源那样照亮。 将定向光的 Direction 指定为 Vector3D,但是没有为定向光指定位置。

  • PointLight:像近处的光源那样照亮。 PointLights 具有一个位置并从该位置投射光。 场景中的对象根据对象相对于光源的位置和距离被照亮。 PointLightBase 公开了 Range 属性,该属性确定一个距离,超过该距离后模型将无法由光源照亮。 PointLight 还公开了多个衰减属性,这些属性确定光源的亮度如何随距离的增加而减小。 可以为光源的衰减指定恒定、线性或二次内插算法。

  • SpotLight:继承自 PointLight。 Spotlights 的照亮方式与 PointLight 类似,但是它既具有位置又具有方向。 它们在 InnerConeAngleOuterConeAngle 属性所设置的锥形区域(以度为单位指定)中投射光。

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

<ModelVisual3D.Content>
    <AmbientLight Color="#333333" />
</ModelVisual3D.Content>
DirectionalLight myDirLight = new DirectionalLight();
Private myDirLight As New DirectionalLight()
myDirLight.Color = Colors.White;
myDirLight.Direction = new Vector3D(-3, -4, -5);
myDirLight.Color = Colors.White
myDirLight.Direction = New Vector3D(-3, -4, -5)
modelGroup.Children.Add(myDirLight);
modelGroup.Children.Add(myDirLight)

转换模型

创建模型时,它们在场景中有特定的位置。 为了在场景中移动、旋转这些模型或者更改这些模型的大小而更改用来定义模型本身的顶点不切实际。 而正如在 2D 中一样,可以向模型应用转换。

每个模型对象都有一个 Transform 属性,你可以使用该属性移动、重新定向模型或调整其大小。 应用转换时,实际上是按照由转换功能指定的矢量或值(以适用者为准)来偏移模型的所有点。 换言之,用户已经转换了在其中定义模型的坐标空间(“模型空间”),但是尚未更改在整个场景的坐标系(“全局空间”)中构成模型几何形状的值。

有关转换模型的详细信息,请参阅 3D 转换概述

对模型进行动画处理

WPF 3D 实现与 2D 图形参与同一个计时和动画系统。 换言之,若要对 3D 场景进行动画处理,需要对其模型的属性进行动画处理。 可以直接对基元的属性进行动画处理,但是通常很容易对用来更改模型位置或外观的转换进行动画处理。 由于可以向 Model3DGroup 对象以及单个模型应用转换,因此可以向 Model3DGroup 的子级应用一组动画,向一组子对象应用另一组动画。 还可以通过对场景的照明属性进行动画处理来实现各种视觉效果。 最后,可以选择通过对照相机的位置或视野进行动画处理来对投影本身进行动画处理。 有关 WPF 计时和动画系统的背景信息,请参阅动画概述情节提要概述Freezable 对象概述主题。

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

假设你希望实现模型看上去是在原地摇摆的效果。 可以选择向模型应用 RotateTransform3D,并对模型从一个矢量旋转到另一个矢量时所围绕的轴进行动画处理。 下面的代码示例演示如何将 Vector3DAnimation 应用于该转换的 Rotation3D 的 Axis 属性,并假设 RotateTransform3D 是应用于具有 TransformGroup 的模型的几个转换之一。

//Define a rotation
RotateTransform3D myRotateTransform = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), 1));
'Define a rotation
Dim myRotateTransform As New RotateTransform3D(New AxisAngleRotation3D(New Vector3D(0, 1, 0), 1))
Vector3DAnimation myVectorAnimation = new Vector3DAnimation(new Vector3D(-1, -1, -1), new Duration(TimeSpan.FromMilliseconds(5000)));
myVectorAnimation.RepeatBehavior = RepeatBehavior.Forever;
Dim myVectorAnimation As New Vector3DAnimation(New Vector3D(-1, -1, -1), New Duration(TimeSpan.FromMilliseconds(5000)))
myVectorAnimation.RepeatBehavior = RepeatBehavior.Forever
myRotateTransform.Rotation.BeginAnimation(AxisAngleRotation3D.AxisProperty, myVectorAnimation);
myRotateTransform.Rotation.BeginAnimation(AxisAngleRotation3D.AxisProperty, myVectorAnimation)
//Add transformation to the model
cube1TransformGroup.Children.Add(myRotateTransform);
'Add transformation to the model
cube1TransformGroup.Children.Add(myRotateTransform)

向窗口中添加 3D 内容

若要呈现场景,请向 Model3DGroup 中添加模型和光源,然后将 Model3DGroup 设置为 ModelVisual3DContent。 将 ModelVisual3D 添加到 Viewport3DChildren 集合中。 通过设置 Camera 属性,向 Viewport3D 添加照相机。

最后,将 Viewport3D 添加到窗口。 在将 Viewport3D 添加为布局元素(如 Canvas)的内容时,可以通过设置 Viewport3D 的 HeightWidth 属性(继承自 FrameworkElement)来指定它的大小。

<UserControl x:Class="HostingWpfUserControlInWf.UserControl1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    >
  
    <Grid>

      <!-- Place a Label control at the top of the view. -->
      <Label 
                HorizontalAlignment="Center" 
                TextBlock.TextAlignment="Center" 
                FontSize="20" 
                Foreground="Red" 
                Content="Model: Cone"/>

      <!-- Viewport3D is the rendering surface. -->
      <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>
    </Grid>
  
</UserControl>

另请参阅