最大程度地提高 WPF 三维性能
在应用程序中使用 Windows Presentation Foundation (WPF) 生成三维控件并包含三维场景时,重要的一点是要考虑性能优化。本主题提供一个影响应用程序性能的三维类和属性的列表,以及使用这些类和属性时优化性能的建议。
本主题假定您已深入了解 Windows Presentation Foundation (WPF) 三维功能。 本文档中的建议适用于“呈现层 2”- 大致定义为支持像素着色器 2.0 版和顶点着色器 2.0 版的硬件。 有关更多详细信息,请参见图形呈现层。
性能影响:高
Property |
建议 |
画笔速度(从最快到最慢): DrawingBrush(已缓存) VisualBrush(已缓存) DrawingBrush(未缓存) VisualBrush(未缓存) |
|
在不需要 Windows Presentation Foundation (WPF) 显式将 Viewport3D 的内容剪辑到 Viewport3D 的矩形时,将 Viewport3D.ClipToBounds 设置为 false。Windows Presentation Foundation (WPF) 的抗锯齿剪辑非常慢,并且 ClipToBounds 在 Viewport3D 上是默认启用的(较慢)。 |
|
如果在执行鼠标命中测试时不需要让 Windows Presentation Foundation (WPF) 考虑 Viewport3D 的内容,将 Viewport3D.IsHitTestVisible 设置为 false。对三维内容的命中测试是以软件进行的,遇到大型网格时可能非常慢。IsHitTestVisible 在 Viewport3D 上是默认启用的(较慢)。 |
|
仅当需要不同的 Material 或 Transform 时,才会创建不同的模型。 否则,请尝试将具有相同 Material 和 Transform 的多个 GeometryModel3D 实例合并到少数几个较大的 GeometryModel3D 和 MeshGeometry3D 实例中。 |
|
网格动画是指按帧更改网格的各个顶点,在 Windows Presentation Foundation (WPF) 中它并非总是那么高效。在修改每个顶点时,为了尽可能降低更改通知对性能的影响,应在对每个顶点执行修改之前将网格与可视化树分离。修改网格之后,再将网格重新附加到可视化树。此外,应尝试尽量减小以这种方式进行动画处理的网格大小。 |
|
3D Antialiasing |
若要提高呈现速度,请通过将附加属性 EdgeMode 设置为 Aliased,在 Viewport3D 上禁用多级采样。 默认情况下,三维抗锯齿在 Microsoft Windows XP 中是禁用的,而在 Windows Vista 中是启用的,每个像素具有 4 个样本。 |
Text |
三维场景中的实时文本(由于位于 DrawingBrush 或 VisualBrush 中,因此是实时文本)非常缓慢。 请尝试改用文本的图像(通过 RenderTargetBitmap),除非文本会发生更改。 |
如果由于该画笔的内容不是静态的而导致必须在三维场景中使用 VisualBrush 或 DrawingBrush,请尝试缓存此画笔,方法是将附加属性 CachingHint 设置为 Cache。 使用 CacheInvalidationThresholdMinimum 和 CacheInvalidationThresholdMaximum 附加属性设置无效缩放的最小和最大阈值,以便不会过度频繁地重新生成缓存的画笔,同时保持所需的质量。 默认情况下不会缓存 DrawingBrush 和 VisualBrush,这表示当每次必须重新呈现使用画笔绘制的内容时,必须首先将画笔的整个内容重新呈现到中间图面。 |
|
BitmapEffect 强制呈现所有受影响的内容,无需硬件加速。 为获取最佳性能,请不要使用 BitmapEffect。 |
性能影响:中
Property |
建议 |
如果通过共享顶点和具有相同的位置、法向量和纹理坐标的顶点以邻接三角形的形式定义网格,只需定义一次每个共享的顶点,然后使用带有 TriangleIndices 的索引来定义三角形。 |
|
当您可以显式控制纹理大小时(例如当您正在使用 RenderTargetBitmap 和/或 ImageBrush 时),请尝试将其大小最小化。 请注意,较低的纹理分辨率会降低显示质量,因此,请在质量和性能之间进行合理选择。 |
|
Opacity |
呈现半透明的三维内容(如反射)时,请通过 Opacity 或 Color 使用画笔或材料上的不透明度属性,而不要通过将 Viewport3D.Opacity 设置为小于 1 的值来创建单独的半透明 Viewport3D。 |
尽可能减少场景中正在使用的 Viewport3D 对象的数目。 将多个三维模型放置到同一个 Viewport3D 中,而不是为每个模型创建单独的 Viewport3D 实例。 |
|
通常,最好重复使用 MeshGeometry3D、GeometryModel3D、Brush 和 Material。 由于它们都是从 Freezable 派生的,因此都具有多个父级。 |
|
当 Freezable 的属性在应用程序中保持不变时,请对其调用 Freeze 方法。 冻结可减少工作集并提高速度。 |
|
当画笔的内容不会发生更改时,请使用 ImageBrush,而不要使用 VisualBrush 或 DrawingBrush。 二维内容可以通过 RenderTargetBitmap 转换为 Image,然后再在 ImageBrush 中使用。 |
|
请不要使用 BackMaterial,除非您确实需要查看 GeometryModel3D 的背面。 |
|
光源速度(从最快到最慢): |
|
尽量使网格大小小于下列限制: TriangleIndices:60,003 个 Int32 实例 |
|
Material 速度(从最快到最慢): |
|
Windows Presentation Foundation (WPF) 三维不会以一致的方式退出不可见的画笔(黑色环境画笔、透明画笔等)。可以考虑在场景中省略这些画笔。 |
|
MaterialGroup 中的每个 Material 都会引起其他呈现过程,因此包含多个材料(即使是简单的材料)会大幅度增加 GPU 的填充请求。 请尽量减少 MaterialGroup 中材料的数目。 |
性能影响:低
Property |
建议 |
如果不需要动画或数据绑定,请不要使用包含多个变换的变换组,而应使用单一 MatrixTransform3D,将其设置为变换组中原本应单独存在的所有变换的积。 |
|
请最大程度地减少场景中的光源数。 场景中光源过多会使 Windows Presentation Foundation (WPF) 动用软件呈现。此限制大致为 110 个 DirectionalLight 对象、70 个 PointLight 对象或 40 个 SpotLight 对象。 |
|
将移动对象与静态对象分隔开来,方法是将移动对象放置到单独的 ModelVisual3D 实例中。 ModelVisual3D 比 GeometryModel3D 更“重”,因为它缓存了变换的边界。 GeometryModel3D 适用于模型;ModelVisual3D 适用于场景节点。 请使用 ModelVisual3D 将 GeometryModel3D 的共享实例放置到场景中。 |
|
请最大程度地减少场景中光源数的更改次数。 每次更改光源数都会强制重新生成和重新编译着色器,除非该配置原来已经存在(并因此而缓存其着色器)。 |
|
Light |
黑色光源是不可见的,但它们会增加呈现时间;请考虑不要使用它们。 |
若要最大程度地减少在 Windows Presentation Foundation (WPF) 中构建大型集合(如 MeshGeometry3D 的 Positions、Normals、TextureCoordinates 和 TriangleIndices)的时间,请在填充值之前预先调整集合大小。 如果可能,请向集合的构造函数传递预填充数据结构(例如数组或列表)。 |