最大程度地提高 WPF 三维性能
使用 Windows Presentation Foundation (WPF) 生成 3D 控件并在应用程序中包含 3D 场景时,请务必考虑性能优化。 本主题提供对应用程序具有性能影响的 3D 类和属性的列表,以及在使用它们时优化性能的建议。
本主题假定你对 Windows Presentation Foundation (WPF) 3D 功能具有深入理解。 本文档中的建议适用于“呈现层 2” - 大致定义为支持像素着色器版本 2.0 和顶点着色器版本 2.0 的硬件。 有关详细信息,请参阅图形呈现层。
性能影响:高
properties | 建议 |
---|---|
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 内容是在软件中完成的,并且对于大型网格可能很慢。 在 Viewport3D 上默认启用 IsHitTestVisible(慢速)。 |
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。 |
性能影响:中
properties | 建议 |
---|---|
MeshGeometry3D | 如果将网格定义为带有共享顶点的邻接三角形,并且这些顶点具有相同的位置、法线和纹理坐标,则仅需定义每个共享顶点一次,然后通过索引 TriangleIndices 定义三角形。 |
ImageBrush | 对纹理大小有显示控制时(使用 RenderTargetBitmap 和/或 ImageBrush 时),尝试最小化纹理大小。 请注意,低分辨率的纹理会降低视觉质量,因此请尝试在质量和性能之间找到合适的平衡。 |
不透明度 | 呈现半透明 3D 内容(如反射)时,请使用画笔或材料的不透明度属性(通过 Opacity 或 Color),而不是通过将 Viewport3D.Opacity 设置为小于 1 的值来创建一个单独的半透明 Viewport3D。 |
Viewport3D | 尽量减少在场景中使用的 Viewport3D 对象的数量。 将许多 3D 模型放在同一个 Viewport3D 中,而不是为每个模型创建单独的 Viewport3D 实例。 |
Freezable | 通常情况下,重复使用 MeshGeometry3DGeometryModel3D、画笔和材料是有益的。 它们都是多父的,因为它们派生自 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 材料的数量。 |
性能影响:低
properties | 建议 |
---|---|
Transform3DGroup | 如果不需要动画或数据绑定,与其使用包含多个转换的转换组,不如使用单个 MatrixTransform3D,将其设置为转换组中独立存在的所有转换的乘积。 |
Light | 最大程度地减少场景中的灯光数量。 场景中的灯光过多将强制 Windows Presentation Foundation (WPF) 回退到软件呈现。 限制大约为 110 个 DirectionalLight 对象、70 个 PointLight 对象或 40 个 SpotLight 对象。 |
ModelVisual3D | 通过将移动对象与静态对象放在不同的 ModelVisual3D 实例中,将它们分隔开。 ModelVisual3D 比 GeometryModel3D“更重”,因为它缓存了转换后的边界。 GeometryModel3D 已优化为模型。ModelVisual3D 已优化为场景节点。 使用 ModelVisual3D 将 GeometryModel3D 的共享实例放入场景中。 |
Light | 最大程度地减少场景中更改灯具数的次数。 每次灯具数的改变都会强制着色器重新生成和重新编译,除非该配置之前已经存在(因此缓存了其着色器)。 |
浅 | 黑光灯将不可见,但它们将增加呈现时间,考虑省略它们。 |
MeshGeometry3D | 要最大程度地减少 Windows Presentation Foundation (WPF) 中大型集合(例如 MeshGeometry3D 的 Positions、Normals、TextureCoordinates 和 TriangleIndices)的构造时间,应在填充值之前预先调整集合的大小。 如果可能,请向集合的构造函数传递预填充的数据结构,例如数组或列表。 |