DrawingVisual与Canvas.OnRender的性能,适用于许多不断变化的形状

时间:2010-02-23 15:36:48

标签: wpf performance

我正在开发一款类似游戏的应用程序,它有多达千种形状(椭圆和线条),不断变换为60fps。阅读excellent article on rendering many moving shapes后,我使用自定义Canvas后代实现了这一点,该后代覆盖OnRender以通过DrawingContext进行绘制。虽然CPU使用率很高,但性能非常合理。

然而,文章建议不断移动形状的最有效方法是使用大量DrawingVisual个实例而不是OnRender。不幸的是,虽然它没有解释为什么在这种情况下应该更快。

以这种方式改变实现并不是一件小事,所以我想在决定进行切换之前了解原因以及它们是否适用于我。为什么DrawingVisual方法会导致CPU使用率低于此方案中的OnRender方法?

4 个答案:

答案 0 :(得分:15)

来自C#2008中的Pro WPF:

  

这些问题引起的问题   应用程序并不复杂   艺术,但纯粹的数量   个别图形元素。即使   你用你的Path元素替换   重量较轻的几何物体,   开销仍将阻碍   应用程序的性能。 WPF   这种情况的解决方案是   使用较低级别的可视图层   模型。基本的想法就是你   将每个图形元素定义为   视觉对象,这是一个非常   轻量化成分少   开销比Geometry对象或   路径对象。

它归结为你正在创建的那些省略号和行中的每一个都是单独的FrameworkElement;这意味着它不仅支持命中测试,还支持布局,输入,焦点,事件,样式,数据绑定,资源和动画。对于你想要做的事情来说,这是一个非常重量级的对象! Visual对象会跳过所有内容并直接从DependencyObject继承。它仍然支持命中测试,坐标转换和边界框计算,但没有形状支持的其他东西。它的重量更轻,可能会极大地提高你的性能。

修改

好的,我第一次误读了你的问题。

如果您使用OnRender,则实际上取决于您创建视觉效果并显示它们的方式。如果您使用DrawingContext并将所有视觉效果添加到单个元素,则这与使用DrawingVisual方法没有什么不同。如果您为创建的每个Visual创建单独的元素,那么这将是一个问题。在我看来,你正在以正确的方式做事。

答案 1 :(得分:8)

答案中的每个人都错了。问题是在绘图上下文中直接渲染形状是否比创建DrawingVisual更快。答案显然是'是'。 DrawLine,DrawEllipse,DrawRectangle等函数不会创建任何UI元素。 DrawingVisual要慢得多,因为它确实创建了一个UI元素,尽管它是一个轻量级元素。答案中的混淆是因为人们只是复制/粘贴DrawingVisual比MSDN中的不同UIElement形状语句表现更好。

答案 2 :(得分:7)

我认为Petzold在这一段中解释过;

  

ScatterPlotVisual类的工作原理   为...创建DrawingVisual对象   每个DataPoint。什么时候的属性   一个DataPoint对象更改,该类   只需要改变DrawingVisual   与该DataPoint相关联。

构建于之前的解释;

  

每当ItemsSource属性   更改,或集合更改,或   DataPoint对象的属性   集合改变了,   ScatterPlotRender调用   InvalidateVisual。这会产生一个   打电话给OnRender   整个散点图

这是你的要求吗?

顺便说一句,this是一个相当新的高性能WPF教程,在该绘图中有数万个点,它也是3D渲染和动画(甚至使用鼠标输入来驱动一些变换)。

答案 3 :(得分:2)

在我的测试中(平移动画),我注意到速度没有差异。我会说使用主机元素进行许多绘制视觉效果要快一些。这种使用许多视觉效果构建可视树的方法可以让您获得更多控制权。此外,当您想要进行复杂的命中测试时,过滤过程会更快,因为您可以跳过视觉效果的整个“分支”