【问题标题】:Java fast pixel operationsJava 快速像素操作
【发布时间】:2011-06-25 15:25:34
【问题描述】:

我想知道如何在 Java 中最好地处理像素操作。我正在使用摆动并绘制一个 1 x 1 像素的矩形非常慢。我需要至少获得 60 fps,而无需使用太多资源。首先对图像进行 blitting 是否意味着可以成功归档?或者一般来说用 Java 来做这件事是个坏主意,我是否需要坚持使用 C 或其他替代方法?

我正在开始编写一个光线投射器,因为我正在使用的 openCL 有一个 Java 包装器,所以我更喜欢在 Java 中工作。

【问题讨论】:

  • 我建议阅读中间图像的概念。这是一个例子 - java2s.com/Code/Java/Advanced-Graphics/IntermediateImages.htm
  • 我认为中间图像技术与我描述的路线一致; blitting 图像。但是我不熟悉Java中这个的速度结果,这是我想知道的。
  • 这种技术在 Java 中无法获得 60fps 的结果,仍然太慢了。
  • 我不确定这里的这些 cmets 如何与下面选择的答案一起使用。 @mre 建议的 Intermediate Image 参考部署 BufferedImage 就像 @Devon_C_Miller 的答案一样。真的很难想象你不能用 60fps 绘制一个 1 x 1 px 的矩形。

标签: java performance swing draw pixel


【解决方案1】:

补充@camickr 的建议:

创建一个 BufferedImage (BI),将其包装在 IconImage 中,将其设置为 JLabel 的图标。将更改绘制到 BI 上并调用 JLabel 的 repaint() 来刷新这些更改。画面的变化。在 BI 中缓存部分图像可以减少绘制例程的工作量。它只需要blit图像,而不是渲染图像。使用 SwingWorkers 部署后台线程来运行计算并将结果传回 EDT 进行绘制。

只要您在谈论静态图像,就可以正常工作。如果您正在考虑更像是视频游戏(一些固定图像和其他移动图像),请查看 VolatileImage。这里有一个很好的描述:http://gpwiki.org/index.php/Java:Tutorials:VolatileImage

更新:

以下给了我超过 80 fps 的速度:

public class Demo extends javax.swing.JPanel {
    private Image src = null;
    public Demo() {
        new Worker().execute();
    }
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (src != null) g.drawImage(src, 0, 0, this);
    }
    private class Worker extends SwingWorker<Void, Image>{
        private final Color[] colors = { Color.red, Color.green, Color.blue };
        protected void process(List<Image> chunks){
            for (Image bufferedImage : chunks){
                src = bufferedImage;
                repaint();
            }
        }
        protected Void doInBackground() throws Exception{
            int frames = 0;
            int[] mem = new int[1024 * 768];
            long start = System.currentTimeMillis();
            long end = start + 15000;
            long last = start;
            while (last < end){
                int col = colors[frames % colors.length].getRGB();
                for (int y = 0; y < 768; y++)
                    for (int x = 0; x < 1024; x++)
                        mem[x + y * 1024] = col;
                Image img = createImage(new MemoryImageSource(1024, 768, mem, 0, 1024));
                BufferedImage bi = new BufferedImage(1024, 768, BufferedImage.TYPE_INT_ARGB);
                Graphics2D g2 = bi.createGraphics();
                g2.drawImage(img, 0, 0, null);
                g2.dispose();
                publish(bi);
                last = System.currentTimeMillis();
                frames++;
            }
            System.err.println("Frames = " + frames + ", fps = " + ((double) frames / (last - start) * 1000));
            return null;
        }
    }
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run(){
                JFrame jf = new JFrame();
                jf.getContentPane().add(new Demo(), BorderLayout.CENTER);
                jf.setSize(1024, 768);
                jf.setVisible(true);
            }
        });
    }
}

【讨论】:

  • 我在 1024x768 图像上用像素填充屏幕的速度为 10fps。知道如何加快速度吗?我正在使用您所说的技术并运行一个 while true 循环进行渲染。
  • 如果您只是渲染到 BI 而没有实际将其绘制到屏幕上,您会获得什么样的性能?通常,光线追踪的瓶颈更多在于计算而不是屏幕更新。每次完成一个屏幕的计算时,尝试只输出 System.currentTimeMillis()。
  • 我正在绘制非计算像素,因此只需逐个像素地填充屏幕。在 320x240 时,我得到 100+ fps,在 1024x768 时,它下降到 10。如果我省略 repaint(),它不会改变结果。
  • 太棒了!非常感谢您。还不知道主要区别是什么;我猜它可能会使用 SwingWorker。
  • 交换 x 和 y 循环的顺序以使其更快(更好的局部性)。
【解决方案2】:

使用 BufferedImage 和 setRGB(...) 方法。然后你在你的绘画程序中绘制整个图像。

【讨论】:

  • 我可以通过这种方式(例如 1024x768 分辨率)符合要求(60 fps)吗?
猜你喜欢
  • 2016-01-23
  • 2022-06-25
  • 1970-01-01
  • 2021-02-10
  • 1970-01-01
  • 2020-10-18
  • 2013-11-10
  • 2011-12-20
  • 2011-09-05
相关资源
最近更新 更多