WPF(过多的绘图可视化元素)导致平移和缩放不流畅。

3
在一个画布中,我有大约2000个派生自FrameworkElement的项目,其中包含大约12000个绘图可视化元素。这个画布表示复杂机器的2D视图,并且具有平移和缩放逻辑。
绘图速度很快,但是当机器/绘图完全加载时,平移和缩放就会非常卡顿。
我可以在.net4中应用位图缓存功能来使其运行得更快。但问题是,当画布缩放以查看细节时,会出现像素块,这非常难看。
有没有什么方法可以加速这个过程?
我找不到任何合理的答案。
我尝试了这样做...首先我有10000个FrameworkElement,它代表简单的形状,如矩形和圆形...速度非常慢。
然后我尝试了一个FrameworkElement,它包含10000个绘图可视化元素...仍然很慢。
然后我尝试了一个包含10000个绘图的绘图可视化元素的FrameworkElement...仍然很慢...

我通过使用位图缓存来解决了这个问题。当缩放级别较低时,显示缓存的绘图(然后缩放和平移是平滑的)。当缩放超过一定级别时,缓存被禁用。在增加的缩放状态下,由于可见元素较少,因此当我们平移时,它不会抖动太多。因此,整体效果就像经过大缩放后,绘图看起来像素化了,但在缓存被取消后一秒钟内变得清晰。 - Socrates
7个回答

2
使用四叉树怎么样?
对于大型地图的二维游戏,显然你不会绘制整个世界,只绘制可见的部分。
使用四叉树可以相对廉价地跟踪对象的位置,稍后在绘制时,你只需要绘制出现在屏幕上的四叉树节点中的可见对象。但是这需要自己编写绘图例程。
下面是我编写的一些代码,用于查找要绘制的内容:https://gamedev.stackexchange.com/questions/29121/organize-a-game-set 此外,
绘制 10K FrameworkElement、12K DrawingVisual 的数量太高了,可能高达一个或两个数量级。如果你必须保留这些类型,则应该在每个容器中进行更多的绘制,这样可以减少一些开销。 这可能会引起你的兴趣(虚拟化 WPF 画布):http://blogs.msdn.com/b/kaelr/archive/2009/05/21/priorityquadtree.aspx 个人认为,我转向了高性能的 OpenGL,但我认为这是一个极端的解决方案 :-)))

2
你是如何实现平移和缩放的?如果这些操作使Canvas的布局无效,那么可能需要在每一帧上进行完整的测量和排列过程(或仅排列),这会随着元素数量的增加而迅速减慢。如果可以使用Canvas的RenderTransform进行操作,则不需要在每次移动时重新计算布局。
另一个尝试的方法是尽可能减少FrameworkElements的数量,也许通过一个中间人将您当前的对象捆绑在一起并输出一个单独的Visual来表示它们在此视图中的所有内容。显然,这样做就不会有相同的交互能力,但我不确定您具体的需求。

1
谢谢你的回复,约翰...请在以下网址找到一个小型示例项目: http://docs.google.com/leaf?id=0BzPnVM2kRr59OWU5MTczM2QtYjUyOC00Y2VjLWI1NzUtYTI3YjRjMTNmNDcx&hl=en&authkey=CKmt0_YM在我的实际软件中,我已经尽可能地打包了相同的视觉元素...除此之外,它会影响交互... 如果可能,请检查一下... 滚动缩放...拖动平移... 当完全缩小时,它是可怕的。 - Socrates

2
我将开始悬赏,我不能一直设置位图缓存,因为图形很糟糕。
所以现在我正在做的是,在右键点击进行平移时,我将所有控件转换为位图缓存,当我释放按钮时,我删除位图缓存。这样,只有当我平移时才会出现丑陋的情况,但非常流畅。
问题是当我将所有内容都转换为位图缓存(或者当我删除它)时,当我完全缩小时需要大约1秒或2秒...等待那么长时间是不可接受的...
至于性能,是的,我们尽可能地冻结所有东西。
编辑:
我刚刚在一台强大的电脑上尝试了一下:双四核3.6ghz,6GB显卡,16 GB内存,SSD,一切......转换所有控件为缓存需要1秒钟......如果我不使用缓存,就会出现很多延迟。

我当时通过使用位图缓存来解决了这个问题。当缩放级别较低时,显示缓存的绘图(然后缩放和平移是平滑的)。当缩放超过一定级别时,缓存将被禁用。在增加缩放状态下,由于可见元素较少,因此当我们平移时,它不会抖动太多。因此,整体效果就像经过大缩放后,绘图看起来像素化了,但在缓存被取消后一秒钟内变得清晰。 - Socrates

2
尝试使用 以使缓存的位图创建两倍于分辨率,这样当您缩放时,它就不会那么像素化。甚至可以尝试三倍分辨率……显然在某个点上会有内存折衷。请注意,位图缓存大小限制为2048x2048。
否则,您可以实现自己的位图缓存策略-也许实现自己的ScrollViewer和IScrollInfo,并使用RenderTargetBitmap创建自己的缓存位图,并将该位图覆盖到画布上(并分离/隐藏其他一组可视化),同时进行平移和缩放。为了避免在开始缩放/平移时创建位图(即渲染所有这些可视化物品)的延迟,您可以在绘图修改后在后台将“机器”呈现为高分辨率图像,以便立即使用。 http://www.codeproject.com/Articles/97871/WPF-simple-zoom-and-drag-support-in-a-ScrollViewer
如果您复杂机器的2D视图是只读/未编辑,则可以尝试使用Deep Zoom。棘手的部分将在生成高分辨率图像和创建.dzi文件方面。但您必须在Web服务器上托管.dzi。 http://www.codeproject.com/Articles/128695/Deep-Zoom-for-WPF 只要您可以生成一组不同分辨率的图像,就可以将它们连接在一起构建.dzi。 http://jimlynn.wordpress.com/2008/11/28/programmatically-create-deep-zoom-collections/ 允许分析.dzi文件。 http://www.deepzoompublisher.com/Viewer/
或者,您可以尝试ZoomableApplication2,声称可以虚拟化一百万个项目……当您放大以减少被处理的元素时,这会有所帮助……但是在正常的1:1视图下不会有帮助。 http://blogs.msdn.com/b/kaelr/archive/2010/08/11/zoomableapplication2-a-million-items.aspx

1

0

不确定是否适用于您的代码,但您可以在可视元素上使用“Freeze”来提高性能。


0

你可以使用新的CacheMode API与.NET 4.0,它将极大地提高性能。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接