Java 2D绘图最佳性能

时间:2020-03-06 14:52:19  来源:igfitidea点击:

我正在编写Java 2D游戏。我正在使用内置的Java 2D图形库,在我从BufferStrategy中从JFrame(有时是全屏)的Canvas中从BufferStrategy获取的Graphics2D上进行绘图。 BufferStrategy是双缓冲的。通过计时器主动进行重新粉刷。我遇到了一些性能问题,尤其是在Linux上。

Java2D有很多创建图形缓冲区和绘制图形的方式,我只是不知道自己是否做对了。我一直在尝试使用graphics2d.getDeviceConfiguration()。createCompatibleVolatileImage,这看起来很有希望,但是我没有确凿的证据证明,如果将绘图代码切换到该代码,它将更快。

以经验,在Java 1.5+中将2D图形渲染到屏幕上最快的方法是什么?请注意,游戏遥遥领先,所以我不想切换到完全不同的绘制方法,例如OpenGL或者游戏引擎。我基本上想知道如何获得使用Graphics2D对象在屏幕上绘制内容的最快方法。

解决方案

确保使用双缓冲,首先在内存中绘制一个大缓冲区,然后在完成所有绘制后刷新到屏幕。

我已经使用Java完成了一些基本的绘图应用程序。我还没有进行任何图形密集型工作,但是我建议我们对所有"重新绘制"调用都拥有良好的处理能力。在父容器上进行一次额外的重画调用可能会使渲染工作量增加一倍。

我们需要记住几件事

1)正在刷新,此链接显示了如何使用swingtimers,这可能是调用重绘的一个不错的选择。弄清楚重新粉刷的情况(如先前的海报所述,这很重要,因此我们不必做过多的工作)。

2)确保只在一个线程中绘制。从多线程更新UI可能会导致令人讨厌的事情。

3)双缓冲。这使渲染更平滑。该网站为我们提供了更多有用的信息

我一直在关注这个问题,希望有人会给我们比我更好的答案。

同时,我找到了以下Sun白皮书,该白皮书是在jdk 1.4的beta版发布之后编写的。关于微调,这里有一些有趣的建议,包括运行时标志(在本文底部):

"针对Solaris和Linux的运行时标志

从SDK的Beta 3版本1.4版开始,无论DGA不可用,无论我们是在本地显示环境还是在远程显示环境中工作,Java 2D默认都将图像存储在pixmap中。我们可以使用pmoffscreen标志覆盖此行为:

-Dsun.java2d.pmoffscreen = true / false

如果将此标志设置为true,则即使DGA可用,也会启用屏幕外像素图支持。如果将此标志设置为false,则禁用屏幕外像素图支持。禁用屏幕外像素图支持可以解决一些渲染问题。 "

这是我脑海中的一些窍门。如果我们更具体并且想要做什么,我可能可以提供更多帮助。听起来像是一场游戏,但我不想假设。

只画你需要的东西!不要一直盲目地调用repaint(),尝试一些兄弟姐妹,例如repaint(Rect)或者repaint(x,y,w,h)。

使用Alpha混合时要格外小心,因为这可能是混合图像/图元的昂贵操作。

尝试尽可能地预渲染/缓存。如果我们发现自己以相同的方式反复绘制圆,请考虑将其绘制到BufferedImage中,然后仅绘制BufferedImage。我们正在牺牲内存来提高速度(典型的游戏/高性能图形)

考虑使用OpenGL,请使用LWJGL的JOGL。 JOGL更像Java,而LWJGL在OpenGL访问的基础上提供了更多的游戏功能。与Swing相比,OpenGL可以绘制数量级(使用适当的硬件和驱动程序)。

我遇到的问题与想法相同。在这里查看我的帖子:

Java2D性能问题

它显示了性能下降的原因以及解决方法。尽管不能保证它在所有平台上都能正常工作。我们会在帖子中看到原因。

这篇文章的答案,Consty的答案以及我自己的研究的综述:

什么有效:

  • 使用" GraphicsConfiguration.createCompatibleImage"来创建与我们所绘制的图像兼容的图像。这是绝对必要的!
  • 通过Canvas.createBufferStrategy使用双缓冲绘图。
  • 使用-Dsun.java2d.opengl = True可以加快绘图速度。
  • 避免使用变换进行缩放。而是缓存要使用的图像的缩放比例版本。
  • 避免半透明的图像!使用位掩码的图像很好,但是半透明在Java2D中非常昂贵。

在使用这些方法的测试中,我将速度提高了10倍至15倍,从而使正确的Java 2D图形成为可能。

如果我们不想使用纯Java 2D,可以选择使用GTGE或者JGame之类的游戏库(在Google上搜索它们),然后轻松访问图形,并提供双缓冲和更简单的绘制命令。

我认为,有一个重要的尚未被提及的东西:缓存所有可能的图像。如果我们有一个对象在屏幕上移动,并且外观变化不大,请将其绘制到图像上,然后在每帧的新位置将图像绘制到屏幕上。即使该对象是一个非常简单的对象,也要这样做,我们可能会为我们节省了多少时间而感到惊讶。渲染位图比渲染图元要快得多。

我们可能还希望查看显式设置渲染提示的情况,并在质量考虑允许的情况下关闭诸如抗锯齿的功能。