Java 2D 绘图的最佳性能

33

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

Java2D有非常多的创建图形缓冲区和绘图的方法,我不知道我是否在做正确的事情。我一直在尝试使用graphics2d.getDeviceConfiguration().createCompatibleVolatileImage,它看起来很有前途,但我没有实际证据表明如果我将绘图代码切换到该方法,它会更快。

根据您的经验,什么是在Java 1.5+中将2D图形渲染到屏幕上的最快方法?请注意,游戏已经相当进展,因此我不想完全切换到不同的绘图方法,比如OpenGL或游戏引擎。我基本上想知道如何以最快的方式使用Graphics2D对象向屏幕绘制图形。


只是出于好奇,这个游戏是关于什么的? :D - Mario Ortegón
回复:Mario Ortegon: http://www.metalbeetle.com/spaceexploration/。我没有在主页上放置链接,因为那只会是隐蔽广告。 - Zarkonnen
1
链接看起来有点奇怪(但那是8年前的事了)。 - Oliver Watkins
9个回答

35

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

有效的方法包括:

  • 使用GraphicsConfiguration.createCompatibleImage创建与所绘制内容兼容的图像。这是非常重要的!
  • 通过Canvas.createBufferStrategy使用双缓冲绘图。
  • 在可用时使用-Dsun.java2d.opengl=True来加快绘图速度。
  • 避免使用变换进行缩放。而应该缓存所要使用的图像的缩放版本。
  • 避免使用半透明图像!位掩码图像很好,但是Java2D中的半透明图像非常耗费资源。

在我的测试中,使用这些方法,我得到了10倍至15倍的速度提升,使得Java 2D图形成为可能。


1
在我的情况下,使用OpenGL标志将我的CPU使用率从25%降低到了13%... - VocoJax

17

我认为我和你一样遇到了相同的问题。 在这里查看我的帖子:

Java2D性能问题

它展示了性能下降的原因以及如何修复它。但不能保证在所有平台上都能正常工作,你会在帖子中看到原因。


12

以下是我能想到的一些技巧。如果您更具体地说明您要做什么,我可能能够提供更多帮助。听起来像是一个游戏,但我不想假设。

只绘制需要的内容!不要盲目地调用repaint(),尝试使用像repaint(Rect)或repaint(x,y,w,h)这样的兄弟方法。

非常小心alpha混合,因为对于混合图像/图元来说,它可能是昂贵的操作。

尽可能预渲染/缓存。如果您发现自己一遍又一遍地以相同的方式绘制一个圆,请考虑将其绘制到BufferedImage中,然后只需绘制BufferedImage即可。您在牺牲内存换取速度(这是游戏/高性能图形的典型特征)。

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


3

我认为还有一个重要的问题没有被提及:尽可能缓存所有图像。如果您有一个在屏幕上移动且外观变化不大的对象,请将其绘制成图像,然后在每个帧中将该图像呈现到屏幕的新位置。即使对象非常简单,也要这样做-您可能会惊讶于节省的时间。渲染位图比渲染基元快得多。

您可能还想查看显式设置渲染提示,并关闭诸如抗锯齿之类的内容(如果质量允许)。


1
我用Java做了一些基本的绘图应用。我没有涉及太多图形密集型的东西,但我建议你要很好地掌握所有“repaint”调用。在父容器上进行额外的重绘调用可能会使您进行渲染的量增加一倍。

1

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

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

"适用于Solaris和Linux的运行时标志

从SDK Beta 3版本1.4开始,Java 2D默认情况下在本地或远程显示环境中没有DGA时将图像存储在像素图中。您可以使用pmoffscreen标志覆盖此行为:

-Dsun.java2d.pmoffscreen=true/false

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


0

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


0

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


2
目前,我使用myCanvas.createBufferStrategy(2)。但我不知道手动创建一个Volatile缓冲区是否会更快。 - Zarkonnen

0

有几件事情需要记住:

1)刷新 this link,展示了如何使用 swingtimers 调用 repaint,这可能是一个良好的选项。解决重绘问题(正如之前的帖子所说,这很重要,这样你就不会做太多的工作)。

2)确保只在一个线程中进行绘图。从多个线程更新 UI 可能会导致一些不好的结果。

3)双缓冲技术。这使得渲染更加流畅。this site 为您提供了更多的好资料。


请翻译以下与编程有关的内容,从英语到中文。仅返回翻译后的文本:链接 链接 最好避免使用 Swing 计时器并依赖线程进行动画。 使用主动渲染而不是依赖 repaint() 进行渲染也是一个好习惯。 - user1210049

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