23

你看到了吗?

在此处输入图像描述

每栋房屋的每块砖都是 16x16 像素的图像。

你可以在这里看到一个基于简单 JavaFX 的版本,其中一些Imageview在 X 和 Y 上移动以产生“构造”的效果。

我只是将其调整为Swing使用paintComponent.

问题: - 使用 JavaFX:我的电脑有问题。您在图片上看到的内容需要 2 秒才能加载,然后它的移动非常缓慢且不稳定。- With Swing: 我不知道如何根据亮度、阴影等调整每个块。所以它看起来像这样:

在此处输入图像描述

我应该选择什么方法?两者都有很大的缺点。我本来希望保留 JavaFX 方法,但也想找到Imageview. 这不应该是个好主意。

4

2 回答 2

41

有关 Swing 优化和实现的信息,请参阅其他答案,因为我的答案是 JavaFX 特定的。

如果您坚持使用 JavaFX 实现,可以尝试以下几点:

  1. 使用node.setCache(true)打开节点缓存。
  2. 使用node.setCacheHint(CacheHint.SPEED)启用高速节点转换。
  3. 提供一个没有效果的实现和另一个有效果的实现,看看没有效果的实现是否明显更好。(如果是这种情况,您可能需要使用更有效的效果链或完全放弃某些效果)。
  4. 检查JavaFX 系统要求,以确保您的设置在硬件/操作系统/驱动程序组合方面满足硬件加速的最低要求。
  5. 如果您正在使用基于区域和 css 的处理,请注意css 系统不会造成太多开销(例如,拥有不使用 css 的代码版本并比较其性能)。
  6. 如果需要,实现细节级别的缩放,(例如,缩小时为整个房子提供单个图像,而不是为每个房子瓷砖提供单独的图像)。
  7. 确保您只加载一次给定的Image并在多个ImageViews中重用它。
  8. 使用分析器来识别瓶颈。
  9. 改变测试 CPU 或显卡以查看其中任何一个是否是瓶颈。
  10. 试用Java 8 预览版,其中包含许多针对 JavaFX 的内部性能优化。
  11. 如果要加载大量图像,请使用背景加载,并在加载图像时在前面播放动画或进度条。
  12. 如果要加载大量图像,请在 Image 构造函数中预先缩放它们,这样它们就不会占用太多内存或(可能)需要额外的处理能力来处理额外的像素(只有在使用大量图像时才需要考虑)不同的非常高分辨率的纹理 - 你似乎没有这样做)。

例如:

Image tile = new Image("tile.png");

Group house = new Group();
house.setCache(true);
house.setCacheHint(CacheHint.SPEED);

Effect lighting = new Lighting();

for (int i = 0; i < houseWidth; i++) {
  // here is the critical part => don't do new ImageView(new Image("tile.png"))
  ImageView tileView = new ImageView(tile));
  tileView.setEffect(lighting);
  tileView.setCache(true);
  tileView.setCacheHint(CacheHint.SPEED);

  house.add(tileView);  
}

Mantrid 的建议很有趣。我确实相信,使用 JavaFX,您不需要自己实现脏矩形算法(因为底层平台能够为您处理脏区域处理)。可能是因为它是一种通用机制,它没有提供特定情况所需的优化级别,在这种情况下,您需要自己处理脏处理(例如,通过从场景图中删除节点并重新添加视情况而定)。

此外,可以通过在 JavaFX 中定义效果,将效果应用到屏幕外 ImageView 节点,然后拍摄屏幕外 ImageView 节点的快照以获得预先计算的图像,来预先计算图像上的模糊/亮度/等。这种技术将允许您重用现有的 JavaFX 效果管道,而无需使用 ConvolveOp 机制重新实现它。也许您可以通过在 ImageView 节点上将 cache 设置为 true 并将 cacheHint 设置为加速来获得相同的性能水平,因为我相信这在幕后做了类似的事情(即以增加内存使用为代价来提高速度)。


JavaFX 场景图非常高效,可以处理数千个节点。但是,您的应用程序中可能有更多。如果上述优化点对您没有帮助,您可能需要计算您的节点数并将您的问题的参考(可能还有一些来源)发布到open-jfx 邮件列表,其中 JavaFX 开发人员了解 JavaFX 应用程序的详细信息优化是。

JavaFX 8 对3D 场景图的支持比 JavaFX 2.2 中的(大部分没用的)3D 场景图要好得多。您当前的应用程序似乎是 psuedo-3d,您可以在其中转换 2D 对象、单独应用照明效果并调整每个图块的亮度以获得 3D 外观。如果是这种情况,使用具有统一 3D 照明模型的完全硬件加速的 3D 场景图最终可能会表现得更好、看起来更好并且更容易使用 - 您必须在应用程序的上下文中对其进行评估以查看它是否是值得将您的应用程序从 2D JavaFX 场景图切换到 3D JavaFX 场景图,或从 JavaFX 切换到 Swing 或libgdx等其他技术。

附录

对 Mizur 的一些附加问题的回答:

那么为什么它们如此耗电呢?

从我的回答中可以看出,性能有很多方面,因此找出一个特定的原因来解释为什么某些东西耗电有时很困难,而且通常是不可能的。有时它是导致性能问题的因素的组合。最大的胜利通常来自优化在最内部循环中执行的内容或通过更改用于解决问题的策略。

如果他们需要这么多,请让我移动瓷砖,或者只是展示,不是吗?

就只为移动的东西消耗资源而言,JavaFX 场景图对此进行了一些优化,缓存提示之类的东西可以进一步提高性能。对于您的特定用例或您使用系统的方式,它们可能还不够。您可能需要更改算法以减少系统负载。

有没有办法用这种 Imageview 技术生成每个建筑物的图像,然后将这些建筑物的图像整合到最终场景中?

是的 - 您可以使用许多图像和节点将建筑物渲染到屏幕外场景,对屏幕外场景进行快照以创建单个图像,然后将该图像覆盖在您的最终场景上。

于 2013-01-22T22:22:54.283 回答
2

在绘制图像之前修改图像的模糊/亮度/等

我自己没有使用过,但这里有一个提示——使用 Swing/AWT Kernel+ConvolveOp 机制:http ://www.java-tips.org/java-se-tips/java.awt.image/styling-digital-带有 convolveop.html 的图像

BufferedImage biSrc = ...
BufferedImage biDest = ...

float[] data = new float[] { 0.0625f, 0.125f, 0.0625f, 0.125f, 0.25f, 0.125f, 0.0625f, 0.125f, 0.0625f };
Kernel kernel = new Kernel(3, 3, data);
ConvolveOp convolve = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
convolve.filter(biSrc, biDest);

操作通过 3x3 矩阵(数据)定义。您可以搜索亮度、模糊等的示例。

图片加载需要 2 秒,但之后移动非常缓慢且生涩

使用脏矩形算法:脏矩形

于 2013-01-22T21:10:42.323 回答