Sim*_*mon 5 c# wpf performance drawingcontext
这是我的第一个问题,但是我是一个很长时间的潜伏者.我将其分为两部分,一部分解释我正在做什么以及为什么我认为这是要走的路,第二部分是我无法为自己解决的实际问题.
我在做什么? 我目前正在开发一个用于渲染二维特征的框架,以便实时显示.您可以在浏览器中考虑Google地图等应用程序,但该框架旨在呈现各种地理数据(而不仅仅是轴对齐的栅格数据,如Google Tiles).
该框架将集成到我们(公司)的最新产品中,该产品是用于台式机和笔记本电脑的WPF应用程序.
因此,我选择了WPF的实际渲染几何只 ; 可见性和遮挡剔除由我自己完成,输入处理(鼠标拾取),移动相机等.
作为实时应用程序,它需要至少达到30 FPS.渲染图像时框架表现得足够:我可以每帧绘制几千个位图而不会出现问题,但多边形数据却成为一个主要问题.
我正在使用WPF渲染相当数量的折线和多边形数据的实际问题,特别是使用DrawingContext和StreamGeometry.到目前为止,我的理解是,如果我需要表现,这就是我要采取的方法.但是,我无法达到我期望的结果.
这就是我用实际数据填充StreamGeometry的方法:
using (StreamGeometryContext ctx = Geometry.Open())
{
foreach (var segment in segments)
{
var first = ToWpf(segment[0]);
ctx.BeginFigure(first, false, false);
// Skip the first point, obviously
List<Point> points = segment.Skip(1).Select(ToWpf).ToList();
ctx.PolyLineTo(points, true, false);
}
}
Geometry.Freeze();
Run Code Online (Sandbox Code Playgroud)
这就是我绘制几何体的方式:
_dc.PushTransform(_mercatorToView);
_dc.DrawGeometry(null, _pen, polyline);
_dc.Pop();
Run Code Online (Sandbox Code Playgroud)
作为测试,我将OpenStreetMap中的ESRI形状加载到我的应用程序中以测试其性能,但我完全不满意:我的测试数据包含~3500个线段,总共约20k行.
将每个段映射到它自己的StreamGeometry表现得非常糟糕,但我已经预料到了:渲染大约需要14秒.
然后我尝试使用多个数字将更多段包装到相同的StreamGeometry中:80 StreamGeometry,渲染大约需要50ms.
但是我得不到比这更好的结果.将行数增加到大约100k使我的应用程序几乎无法使用:渲染需要超过100毫秒. 除了在渲染矢量数据时同时冻结几何体和笔,我还能做些什么呢?
我现在更喜欢使用DirectX而不是依赖WPF来做它,因为某些东西似乎非常错误.
编辑
为了进一步阐明我在做什么:该应用程序实时显示地理数据,非常像浏览器中的谷歌地图等应用程序:但它应该可视化更多,更多的数据.您可能知道,谷歌地图允许缩放和平移,它需要> 25 FPS才能显示为流畅的动画; 任何不足都不会流利.
*对不起,我不应该在实际产品发布之前上传这个视频.然而,您可以设想像谷歌地图这样的东西,但是有大量的矢量数据(多边形和折线).*
有两种解决方案,其中一种经常被陈述:
在位图中缓存重图
实现看起来有点简单,但我发现这种方法存在一些问题:为了正确实现平移,我需要避免每帧都绘制繁重的东西,因此我可以选择在平移时不更新缓存的位图相机,或创建一个覆盖比视口更大的区域的位图,这样我只需要经常更新缓存的位图.
第二个"问题"与缩放有关.然而,它更像是一个视觉神器而不是一个真正的问题:由于缓存的位图无法以30 FPS正确更新,因此我需要在缩放时避免这种情况.我可以在缩放时很好地缩放位图,只在缩放结束时创建一个新的位图,但折线的宽度不会有恒定的厚度,尽管它们应该.
这种方法确实似乎被MapInfo使用,但我不能说我太喜欢它了.它似乎是最容易实现的.
将几何体拆分为不同的绘图视觉效果
这种方法似乎以不同的方式处理问题.我不确定这种方法是否有效:这取决于我是否正确理解WPF应该如何在这个领域工作.我不应该使用一个DrawingVisual来绘制所有需要绘制的东西,而应该使用几个,这样每个人都不需要使用RenderOpened().我可以简单地更改参数,例如上面示例中的矩阵,以反映摄像机平移和移动.但是我也看到了这种方法的一些问题:平移摄像机将不可避免地将新几何体带入视口,因此我需要执行类似于第一种方法的操作,实际渲染当前不可见的东西,但可能会变得可见由于相机移位; 绘制一切都是不可能的,因为对于相当少量的数据可能需要花费很多时间.
与两种方法相关的 问题这两种方法都无法解决的一个大问题是,即使整体帧速率稳定,偶尔也会在更新缓存的位图时进行预取(好吧,如果缓存的位图只是当相机不再平移时更新或调用RenderOpen来绘制可见的几何体块,似乎是不可避免的.
到目前为止我的想法
由于这些是我遇到的唯一两个解决方案(我已经公平分享了一年多的谷歌搜索),我想到目前为止唯一的解决方案就是接受即使是功能最强大的GPU上的帧速率的提升(它应该能够每秒光栅化数亿个基元),视口的延迟更新(在位图不再移动时仅更新位图的情况下)或根本不使用WPF并使用DirectX直.
我很高兴能得到帮助,但是我不能说到目前为止我对WPF渲染性能印象深刻.
要提高 2D WPF 渲染性能,您可以查看 RenderTargetBitmap (对于 WPF >= 3.5)或BitmapCache类(对于 WPF >= 4)。
这些类用于Cached Composition
来自MSDN:
通过使用新的 BitmapCache 和 BitmapCacheBrush 类,您可以将可视化树的复杂部分缓存为位图,并大大缩短渲染时间。位图仍然响应用户输入,例如鼠标单击,并且您可以将其绘制到其他元素上,就像任何画笔一样。