.NET WPF 三维模型
文章目录
- .NET WPF 三维模型
- 1 Viewport3D
- 1.1 3D 坐标系
- 1.2 核心组件
- 1.2.1 相机 (Camera)
- 1.2.2 光源 (Light)
- 1.2.3 3D 模型(Model3D)
- 1.3 模型纹理(Material)
- 1.4 完整示例:创建坐标轴与立方体
- 1.5 转换模型
- 1.6 性能
- 1.6.1 性能影响:高
- 1.6.2 性能影响:中
- 1.6.3 性能影响:低
- 1.7 常见问题
- 1.8 扩展工具
.NET WPF 三维模型
1 Viewport3D
- 作用:用于在 WPF 2D 界面中渲染3D图形,结合了3D模型、光源和相机视角。
- 命名空间:
System.Windows.Controls.Viewport3D
- 依赖项:需添加
PresentationCore
和WindowsBase
程序集引用。
1.1 3D 坐标系
2D 图形的 WPF 坐标系将原点定位在呈现区域(通常是屏幕)的左上角。 在 2D 系统中,x 轴上的正值朝右,y 轴上的正值朝下。 但是,在 3D 坐标系中,原点位于呈现区域的中心,x 轴上的正值朝右,但是 y 轴上的正值朝上,z 轴上的正值从原点向外朝向观察者。
1.2 核心组件
1.2.1 相机 (Camera)
创建 3D 场景时,实际上是要创建 3D 对象的 2D 表示形式。 由于 3D 场景的外观会因观察者的观察位置而异,因此必须指定观察位置。 可以使用 Camera 类来为 3D 场景指定观察位置。
了解 3D 场景如何在 2D 图面上表示的另一种方法就是将场景描述为到观察图面上的投影。 使用 ProjectionCamera,可以指定不同的投影及其属性,以更改观察者查看 3D 模型的方式。 PerspectiveCamera 指定用来对场景进行透视收缩的投影。 换言之,PerspectiveCamera 提供消失点透视。 可以指定照相机在场景坐标系中的位置、照相机的方向和视野以及用来定义场景中“向上”方向的矢量。 下图阐释了 PerspectiveCamera 的投影。
ProjectionCamera 的 NearPlaneDistance 和 FarPlaneDistance 属性限制照相机的投影范围。 由于照相机可以位于场景中的任何位置,因此照相机实际上可能会位于模型内部或者紧靠模型,这使正确区分对象变得很困难。 通过 NearPlaneDistance,可以指定一个距离照相机的最小距离,超过该距离后即不绘制对象。 相反,使用 FarPlaneDistance,可以指定一个距离照相机的距离(超过该距离后即不绘制对象),从而确保因距离太远而无法识别的对象不包括在场景中。
OrthographicCamera 指定 3D 模型到 2D 可视图面上的正投影。 与其他照相机一样,它指定位置、观察方向和“向上”方向。 但是,与 PerspectiveCamera 不同的是,OrthographicCamera 描述了不包括透视收缩的投影。 换言之,OrthographicCamera 描述了一个侧面平行的取景框,而不是侧面汇集在照相机中一点的取景框。 下图演示使用 PerspectiveCamera 和 OrthographicCamera 查看同一模型时的情况。
Model3D 是表示泛型 3D 对象的抽象基类。 若要生成 3D 场景,需要一些要查看的对象,而且构成场景图的对象必须派生自 Model3D。 目前,WPF 支持用 GeometryModel3D 对几何图形进行建模。 此模型的 Geometry 属性采用网格基元。
若要生成模型,请首先生成一个基元或网格。 3D 基元是单个 3D 实体中的顶点的集合。 大多数 3D 系统都提供在最简单的闭合图(由三个顶点定义的三角形)上建模的基元。 由于三角形的三个点在一个平面上,因此可以继续添加三角形,以便对网格这样较为复杂的形状建模。
WPF 3D 系统目前提供 MeshGeometry3D 类,使用该类可以指定任何几何图形;它目前不支持预定义的 3D 基元(如球体和立方体)。 首先通过将三角形顶点的列表指定为 Positions 属性来创建 MeshGeometry3D。 每个顶点都指定为 Point3D。 (在 XAML 中,将该属性指定为三个一组的数字列表,每组中的三个数字表示每个顶点的坐标。)根据网格的几何形状,网格可能会由多个三角形组成,有些三角形共用相同的角(顶点)。 要正确绘制网格,WPF 需要有关哪些顶点由哪些三角形共用的信息。 可以通过指定具有 TriangleIndices 属性的三角形索引列表来提供此信息。 此列表指定在 Positions 列表中指定的点将按哪种顺序确定三角形。
控制观察3D场景的视角,常用类型:
<Viewport3D.Camera><!-- 透视相机(模拟人眼视角) --><PerspectiveCamera Position="0,0,5" LookDirection="0,0,-1" UpDirection="0,1,0" FieldOfView="60"/><!-- 或正交相机(无透视变形) --><OrthographicCamera Position="0,0,5" Width="10"/>
</Viewport3D.Camera>
1.2.2 光源 (Light)
与实际的光一样,3D 图形中的光能够使图面可见。 更确切地说,光确定了场景的哪个部分将包括在投影中。 WPF 中的光对象创建了各种光和阴影效果,并且按照各种实际光的行为进行了建模。 至少在场景中包括一个光源,否则模型将不可见。
下面的光源派生自基类 Light:
-
AmbientLight:它所提供的环境光以一致的方式照亮所有对象,这与对象的位置或方向无关。
-
DirectionalLight:像远处的光源那样照亮。 将定向光的 Direction 指定为 Vector3D,但是没有为定向光指定位置。
-
PointLight:像近处的光源那样照亮。 PointLights 具有一个位置并从该位置投射光。 场景中的对象根据对象相对于光源的位置和距离被照亮。 PointLightBase 公开了 Range 属性,该属性确定一个距离,超过该距离后模型将无法由光源照亮。 PointLight 还公开了多个衰减属性,这些属性确定光源的亮度如何随距离的增加而减小。 可以为光源的衰减指定恒定、线性或二次内插算法。
-
SpotLight:继承自 PointLight。 Spotlights 的照亮方式与 PointLight 类似,但是它既具有位置又具有方向。 它们在 InnerConeAngle 和 OuterConeAngle 属性所设置的锥形区域(以度为单位指定)中投射光。
光源是 Model3D 对象,因此可以转换光源属性并对光源属性(包括位置、颜色、方向和范围)进行动画处理。
<ModelVisual3D><ModelVisual3D.Content><DirectionalLight Color="White" Direction="-1,-1,-1" /></ModelVisual3D.Content>
</ModelVisual3D>
1.2.3 3D 模型(Model3D)
Model3D 是表示泛型 3D 对象的抽象基类。 若要生成 3D 场景,需要一些要查看的对象,而且构成场景图的对象必须派生自 Model3D。 目前,WPF 支持用 GeometryModel3D 对几何图形进行建模。 此模型的 Geometry 属性采用网格基元。
若要生成模型,请首先生成一个基元或网格。 3D 基元是单个 3D 实体中的顶点的集合。 大多数 3D 系统都提供在最简单的闭合图(由三个顶点定义的三角形)上建模的基元。 由于三角形的三个点在一个平面上,因此可以继续添加三角形,以便对网格这样较为复杂的形状建模。
WPF 3D 系统目前提供 MeshGeometry3D 类,使用该类可以指定任何几何图形;它目前不支持预定义的 3D 基元(如球体和立方体)。 首先通过将三角形顶点的列表指定为 Positions 属性来创建 MeshGeometry3D。 每个顶点都指定为 Point3D。 (在 XAML 中,将该属性指定为三个一组的数字列表,每组中的三个数字表示每个顶点的坐标。)根据网格的几何形状,网格可能会由多个三角形组成,有些三角形共用相同的角(顶点)。 要正确绘制网格,WPF 需要有关哪些顶点由哪些三角形共用的信息。 可以通过指定具有 TriangleIndices 属性的三角形索引列表来提供此信息。 此列表指定在 Positions 列表中指定的点将按哪种顺序确定三角形。
由 GeometryModel3D
定义,包含几何形状和材质:
<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>
</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) 的顺序组合而成,第二个三角形将按照类似方式确定。
可以通过为 Normals 和 TextureCoordinates 属性指定值来继续定义模型。 为了呈现模型的图面,图形系统需要有关曲面在任何给定三角形上的朝向信息。 图形系统使用此信息来针对该模型进行照明计算:正对光源的图面比偏离光源的图面显得更亮。 尽管 WPF 可以使用位置坐标来确定默认的法矢量,但是你还可以指定不同的法矢量来近似计算曲面的外观。
TextureCoordinates 属性指定 Point 的集合,用于通知图形系统如何将确定纹理绘制方式的坐标映射到网格的顶点。 TextureCoordinates 指定为 0 和 1 之间(包含这两个值)的值。 与 Normals 属性一样,图形系统可以计算默认纹理坐标,但你可以选择设置不同的纹理坐标来控制包括部分重复图案的纹理的映射。
1.3 模型纹理(Material)
为了使网格看上去像三维对象,必须向其应用纹理,以便覆盖由顶点和三角形定义的图面,从而使其可以由照相机照明和投影。 在 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 的子级在多个呈现过程中按照从头到尾的顺序来应用。
1.4 完整示例:创建坐标轴与立方体
<Viewport3D><!-- 相机设置 --><Viewport3D.Camera><PerspectiveCameraFarPlaneDistance="100"FieldOfView="45"LookDirection="-1,-1,-1"NearPlaneDistance="0.5"Position="3,3,3"UpDirection="0,1,0" /></Viewport3D.Camera><!-- 光源 --><ModelVisual3D><ModelVisual3D.Content><DirectionalLight Direction="-1,-1,-1" Color="White" /></ModelVisual3D.Content></ModelVisual3D><!-- 立方体模型 --><ModelVisual3D><ModelVisual3D.Content><GeometryModel3D><GeometryModel3D.Geometry><MeshGeometry3D Positions="0,0,0 1,0,0 1,1,0 0,1,0 0,0,-1 1,0,-1 1,1,-1 0,1,-1 " TriangleIndices=" 0,1,2 0,2,3 4,7,6 4,6,5 0,3,7 7,4,0 1,5,6 1,6,2 3,2,6 3,6,7 0,4,5 0,5,1 " /></GeometryModel3D.Geometry><GeometryModel3D.Material><DiffuseMaterial><DiffuseMaterial.Brush><SolidColorBrush Color="Yellow" /></DiffuseMaterial.Brush></DiffuseMaterial></GeometryModel3D.Material></GeometryModel3D></ModelVisual3D.Content></ModelVisual3D><!-- X轴(红色) --><ModelVisual3D><ModelVisual3D.Content><GeometryModel3D><GeometryModel3D.Geometry><MeshGeometry3D Positions="-1,-0.01,0.01 2,-0.01,0.01 2,0.01,0.01 -1,0.01,0.01 -1,-0.01,-0.01 2,-0.01,-0.01 2,0.01,-0.01 -1,0.01,-0.01 2,0.05,0.05 2,-0.05,0.05 2,-0.05,-0.05 2,0.05,-0.05 2.2,0,0" TriangleIndices=" 0,1,2 0,2,3 4,7,6 4,6,5 0,3,7 0,7,4 1,5,6 1,6,2 3,2,6 3,6,7 0,4,5 0,5,1 8,10,9 8,11,10 12,8,9 12,9,10 12,10,11 12,11,8" /></GeometryModel3D.Geometry><GeometryModel3D.Material><DiffuseMaterial Brush="Red" /></GeometryModel3D.Material></GeometryModel3D></ModelVisual3D.Content></ModelVisual3D><!-- Y轴(绿色) --><ModelVisual3D><ModelVisual3D.Content><GeometryModel3D><GeometryModel3D.Geometry><MeshGeometry3D Positions="-0.01,-1,0.01 0.01,-1,0.01 0.01,2,0.01 -0.01,2,0.01 -0.01,-1,-0.01 0.01,-1,-0.01 0.01,2,-0.01 -0.01,2,-0.01 0.05,2,0.05 0.05,2,-0.05 -0.05,2,-0.05 -0.05,2,0.05 0,2.2,0" TriangleIndices="0,1,2 0,2,3 4,7,6 4,6,5 0,3,7 0,7,4 1,5,6 1,6,2 3,2,6 3,6,7 0,4,5 0,5,1 8,10,9 8,11,10 12,8,9 12,9,10 12,10,11 12,11,8" /></GeometryModel3D.Geometry><GeometryModel3D.Material><DiffuseMaterial Brush="Green" /></GeometryModel3D.Material></GeometryModel3D></ModelVisual3D.Content></ModelVisual3D><!-- Y轴(蓝色) --><ModelVisual3D><ModelVisual3D.Content><GeometryModel3D><GeometryModel3D.Geometry><MeshGeometry3D Positions="-0.01,-0.01,1 0.01,-0.01,1 0.01,0.01,1 -0.01,0.01,1 -0.01,-0.01,-4 0.01,-0.01,-4 0.01,0.01,-4 -0.01,0.01,-4 0.05,0.05,1 -0.05,0.05,1 -0.05,-0.05,1 0.05,-0.05,1 0,0,1.2" TriangleIndices="0,1,2 0,2,3 4,7,6 4,6,5 0,3,7 0,7,4 1,5,6 1,6,2 3,2,6 3,6,7 0,4,5 0,5,1 8,10,9 8,11,10 12,8,9 12,9,10 12,10,11 12,11,8" /></GeometryModel3D.Geometry><GeometryModel3D.Material><DiffuseMaterial Brush="Blue" /></GeometryModel3D.Material></GeometryModel3D></ModelVisual3D.Content></ModelVisual3D>
</Viewport3D>
1.5 转换模型
创建模型时,它们在场景中具有特定位置。 若要在场景中移动这些模型、旋转模型或更改其大小,则更改定义模型本身的顶点并不实用。每个模型对象都有一个 Transform 属性,可以使用该属性移动、重新定位或调整模型的大小。 应用转换时,实际上是按照由转换功能指定的矢量或值(以适用者为准)来偏移模型的所有点。 换句话说,你已转换模型在其中定义的坐标空间(“模型空间”),但你尚未更改构成整个场景坐标系(“世界空间”)中模型几何图形的值。
3D 转换继承自抽象基类 Transform3D;这些包括仿射变换类 TranslateTransform3D、ScaleTransform3D和 RotateTransform3D。 Windows Presentation Foundation (WPF) 3D 系统还提供 MatrixTransform3D 类,使你可以在更简洁的矩阵操作中指定相同的转换。
TranslateTransform3D 按照您通过 OffsetX、OffsetY和 OffsetZ 属性指定的偏移向量方向移动 Model3D 中的所有点。 例如,给定立方体(2,2,2)的一个顶点时,偏移量为(0,1.6,1)会将该顶点(2,2,2,2)移动到(2,3.6,3)。 立方体的顶点在模型空间中仍然是(2,2,2),但现在模型空间与世界空间的关系已改变,因此在世界空间中,模型空间中的(2,2,2)对应为(2,3.6,3)。
1.6 性能
1.6.1 性能影响:高
属性 | 建议 |
---|---|
Brush | 画笔速度(最快至慢): SolidColorBrush > LinearGradientBrush > ImageBrush > DrawingBrush (缓存) > VisualBrush (缓存) > RadialGradientBrush > DrawingBrush (未缓存) > VisualBrush (未缓存) |
ClipToBoundsProperty | 如果不需要使 Windows Presentation Foundation (WPF) 显式地将 Viewport3D 的内容剪裁到 Viewport3D 的矩形,请将 Viewport3D.ClipToBounds 设置为 false。 Windows Presentation Foundation (WPF) 的抗锯齿剪裁可能非常慢,并且在 Viewport3D 上默认启用ClipToBounds (慢速)。 |
IsHitTestVisible | 如果在执行鼠标点击测试时不需要 Windows Presentation Foundation (WPF) 考虑 Viewport3D 的内容,请将 Viewport3D.IsHitTestVisible 设置为 false。 点击测试 3D 内容是在软件中完成的,并且对于大型网格可能很慢。 默认情况下,IsHitTestVisible 在 Viewport3D上被启用(慢)。 |
GeometryModel3D | 仅当它们需要不同的材料或转换时,才创建不同的模型。 否则,请尝试将许多具有相同材料和转换的 GeometryModel3D 实例合并为几个更大的 GeometryModel3D 和 MeshGeometry3D 实例。 |
MeshGeometry3D | 在 Windows Presentation Foundation(WPF)中,网格动画(每帧更改网格的各个顶点)并不总是高效的。 要在修改每个顶点时尽量减少更改通知的性能影响,请在执行每顶点修改之前将网格从可视树中分离出来。 修改网格后,将其重新附加到可视化树。 此外,尽量减小以这种方式进行动画处理的网格大小。 |
3D 抗锯齿 | 为了提高渲染速度,可通过将附加属性 EdgeMode 设置为 Aliased 来禁用 Viewport3D 上的多重采样。 默认情况下,3D 抗锯齿功能在 Windows 上启用,每个像素有 4 个样本。 |
文本 | 在 3D 场景中的实时文本(实时是因为它在 DrawingBrush 或 VisualBrush 中)可能会很慢。 尝试使用文本的图像(通过 RenderTargetBitmap),除非文本将更改。 |
TileBrush | 如果必须在 3D 场景中使用 VisualBrush 或 DrawingBrush,因为画笔的内容不是静态的,请尝试缓存画笔(将附加属性 CachingHint 设置为 Cache )。 设置最小和最大缩放无效阈值(使用附加属性 CacheInvalidationThresholdMinimum 和 CacheInvalidationThresholdMaximum),以便缓存的画笔不会太频繁地重新生成,同时仍然保持所需的质量级别。 默认情况下,不会缓存 DrawingBrush 和 VisualBrush,这意味着每次使用画笔绘制的内容都必须重新呈现时,必须首先将画笔的全部内容重新呈现到中间图面。 |
BitmapEffect | BitmapEffect 强制呈现所有受影响的内容,而无需硬件加速。 为了获得最佳性能,请勿使用 BitmapEffect。 |
1.6.2 性能影响:中
属性 | 建议 |
---|---|
MeshGeometry3D | 如果将网格定义为共享顶点且相邻的三角形,并且这些顶点具有相同的位置、法线和纹理坐标,则每个共享顶点仅需定义一次,然后使用TriangleIndices索引来指定三角形。 |
ImageBrush | 当你对大小有显式控制时(使用 RenderTargetBitmap 和/或 ImageBrush时),请尝试最小化纹理大小。 请注意,分辨率较低的纹理可以降低视觉质量,因此请尝试在质量和性能之间找到适当的平衡。 |
不透明度 | 呈现半透明 3D 内容(如反射)时,在画笔或材料(通过 Opacity 或 Color)上使用不透明度属性,而不是通过将 Viewport3D.Opacity 设置为小于 1 的值来创建单独的半透明 Viewport3D。 |
Viewport3D | 最大程度地减少你在场景中使用的 Viewport3D 对象数。 在同一 Viewport3D 中放置许多 3D 模型,而不是为每个模型创建单独的 Viewport3D 实例。 |
Freezable | 通常,重复使用 MeshGeometry3D、GeometryModel3D、画笔和材料是有益的。 它们都是多父的,因为它们派生自 Freezable 。 |
Freezable | 当“可冻结”的属性在应用程序中保持不变时,对其调用 Freeze 方法。 冻结可以减少工作集,提高速度。 |
Brush | 在画笔内容不会更改时,请使用 ImageBrush 而不是 VisualBrush 或 DrawingBrush。 2D 内容可以通过 RenderTargetBitmap 转换为 Image,然后在 ImageBrush 中使用。 |
BackMaterial | 除非你实际上需要看到 GeometryModel3D 的背面,否则不要使用 BackMaterial。 |
Light | 光速(最快至最慢): AmbientLight DirectionalLight PointLight SpotLight |
MeshGeometry3D | 尝试将网格大小保持在以下限制之下: Positions:20,001 个 Point3D 实例 TriangleIndices:60,003 个 Int32 实例 |
Material | 材料速度(最快至慢): EmissiveMaterial DiffuseMaterial SpecularMaterial |
Brush | Windows Presentation Foundation (WPF) 3D 不会以一致的方式选择退出不可见的画笔(黑色环境画笔和清除画笔等)。 请考虑从场景中省略这些内容。 |
MaterialGroup | MaterialGroup 中的每一个 Material 都会导致另一个呈现传递,因此包括许多材料,甚至是简单的材料,都可以显著增加 GPU 上的填充需求。 尽量减少 MaterialGroup 材料的数量。 |
1.6.3 性能影响:低
属性 | 建议 |
---|---|
Transform3DGroup | 如果不需要动画或数据绑定,与其使用包含多个转换的转换组,不如使用单个 MatrixTransform3D,将其设置为转换组中独立存在的所有转换的乘积。 |
Light | 最大程度地减少场景中的灯光数量。 场景中的灯光过多将迫使 Windows Presentation Foundation (WPF) 回退到软件渲染。 限制约为 110 个 DirectionalLight 对象、70 个 PointLight 对象或 40 个 SpotLight 对象。 |
ModelVisual3D | 通过将移动对象与静态对象置于不同的 ModelVisual3D 实例中,将它们分开。 ModelVisual3D 比 GeometryModel3D 更“负担重”,因为它缓存了转换后的边界。 GeometryModel3D 已优化为模型;ModelVisual3D 已优化为场景节点。 使用 ModelVisual3D 将 GeometryModel3D 的共享实例放入场景中。 |
Light | 最大程度地减少更改场景中的灯数的次数。 光计数的每个更改都强制着色器重新生成和重新编译,除非以前存在该配置(因此缓存了着色器)。 |
Light | 黑光灯不可见,但它们会增加渲染时间,可以考虑省略。 |
MeshGeometry3D | 若要最大程度地减少 Windows Presentation Foundation(WPF)中大型集合的构造时间,例如 MeshGeometry3D 的 Positions、Normals、TextureCoordinates和 TriangleIndices,在值填充之前预先调整集合的大小。 如果可能,请向集合的构造函数传递预填充的数据结构,例如数组或列表。 |
1.7 常见问题
-
模型不可见:
- 检查相机位置和观察方向
- 确认法向量方向是否正确(使用
Vector3D.CrossProduct
计算) - 验证光源是否设置
-
锯齿问题:启用抗锯齿
RenderOptions.SetEdgeMode(viewport3D, EdgeMode.Aliased); RenderOptions.SetBitmapScalingMode(viewport3D, BitmapScalingMode.HighQuality);
1.8 扩展工具
- Helix Toolkit:开源3D库(提供球体、圆柱等预制形状,支持直接从obj、3ds等模型文件加载为GeometryModel3D)