我的情况: 我目前正在从事一个项目,该项目以图形方式显示来自多个工业机器的大量数据。该项目是Winforms / C#项目。当前,我正在使用“ System.Drawing”命名空间提供的Graphics对象中的DrawLine方法。当操纵点数超过500+左右的图形时,延迟非常明显,甚至会导致绘制方法超时。明确地说,我对开发自己的绘图程序感兴趣,并且不想使用另一个已有的程序。
我的观察结果: 遍历互联网时,我可以看到类似下图的图表。我的假设是,即使在下面的图形中绘制了五个或六个点,在实际数据点之间也必须绘制数百个“中间”点(以获取每个数据点之间的平滑曲线)。这样的图形调整大小后非常平滑。
我的问题:
如何获得某些现代(超级用户友好)绘图程序所享有的性能?
在一个理想的世界中,拥有一个超过1000个点的图形将是一件很不错的事情,用户可以轻松地调整大小和移动它,但是有可能吗?
答案 0 :(得分:1)
最有可能使用贝塞尔曲线绘制(填充)“凉爽”曲线,该曲线由少量的所谓控制点定义。诸如System.Drawing之类的API已针对此类图形基元进行了优化和高效,而这些图形基元几乎不需要函数调用。
如果曲线不平滑,也许可以丢弃点而不会丢失细节,但这取决于您的数据。
最后的办法可能是编写自己的渲染算法,该算法利用您的特定数据并通过直接像素访问而不是执行图形调用来生成图像。然后将图像反白显示。
此选项需要对图形渲染有很好的了解。
答案 1 :(得分:1)
您的问题的答案看似简单。用GPU编程实现图形! .Net有多个GPU编程库,例如Alea GPU。 GPU旨在解决异步问题,例如图形显示。原因是GPU可以使用其数千个线程同时执行独立任务。对GPU进行编程并不是一件容易的事,因为一次执行的线程数量很大,因此您可能需要重新考虑重新实现自己的绘图应用程序。
有趣的事实:您可以使用GPU编程来提高任何异步问题的性能,而不仅仅是图形问题。
答案 2 :(得分:1)
我的观察:
虽然有很多方法可以压缩系统的每一点性能来显示图形,但我真诚地认为您不能从此问题的答案中找到解决方案。但是您可以找到很多线索。
在绘制简单图形时出现性能问题,而“现代应用程序”在渲染数千个点时没有问题,那为什么呢?游戏可以4K分辨率每秒渲染60帧以上,并且不能在表面上渲染一帧虚拟图形。
他们是如何做到的?好吧,他们 作弊 进行了优化。
如果您绘制的不是每个点,而是仅绘制有意义的点,并通过像@ yves-daoust建议的那样弯曲来填充其余点,则可以节省一些绘制时间。就像MP3压缩音频一样,它只是删除了您最有可能听不到的部分。
如果像建议的{tigran一样启用DoubleBuffering
,结果将更有效地显示在屏幕上,或者更好的是,您可以在另一个线程中绘制图形,然后绘制该图形,而不是在每个OnPaint中重新绘制它。
您可以使用Invalidate(Rect)方法仅更新图形的相关部分。
您可以按照@ yves-daoust的建议,使用直接位操作将图形绘制为位图,这可能会大大提高性能,但是您必须实现所有疯狂的功能。
虽然Graphics
对象不使用GDI,但是GDI +对许多不太复杂的绘图操作进行了很好的优化,但是您可以使用针对DirectX和Skia等性能进行了优化的图形库。
我的建议: 如果您坚持要绘制所有内容,则可以使用C#获得一些有关Graphics的书籍,并与他们共度美好时光。如果没有,那么请获取一些低成本的小尺寸图表库并完成它。
我的情况: 我已经在Pascal 6.0(DOS时代)中实现了一个简单的线条绘制算法,使用BGI,使用中断,使用直接内存访问和使用IO端口。略读代码后,可以说我正在使用BDSM。
答案 3 :(得分:-2)
因此,如果您自己编写(为什么?),则确实需要避免System.Drawing,因为它非常慢。最好的解决方案是使用DirectX来利用计算机中的GPU,并让他们去做自己最擅长的事情。上次查看System.Drawing时,我仅点击了单个CPU内核,而且速度非常慢,因此,如果您有数百万个数据点,它将无法扩展。
这就是为什么有第三方解决方案的原因,因为他们已经有一个团队这样做。如果您只是为了娱乐或自我探索而这样做,那很好,但是如果它是真正产品的一部分,那么您将很难建立比其他团队更好的产品。 ChartFX是目前为止我所见过的性能最好的产品之一,但是我几乎没有尝试过所有产品,而且我敢肯定还有其他产品可能也更好。