我需要绘制动画帧,其中每个像素都是通过算法动态计算的。因此,全屏动画可能每帧需要进行数百万次操作。我希望获得最高的刷新率,如果可能的话,最好每秒20到30+帧。

有人可以告诉我如何设计/编写高度优化的体系结构,以用Java快速刷新帧吗?

这需要独立于平台,因此我无法利用硬件加速。该代码将在每个用户的计算机上执行,而不是在中央服务器上执行。当然,从简化每个帧内生成像素值的算法的角度来看,我将分别进行处理,但是这个问题是关于帧间高速逐帧刷新的体系结构,与所使用的算法无关在每个帧内生成像素值。例如,在此帖子的答案中,我正在寻找使用以下方法:BufferedImage,双缓冲,多线程,加速的屏幕外图像,其他帧间方法等。

我在下面编写了一些示例代码来模拟该问题。在我的笔记本电脑上以全屏显示时,下面的代码每帧使用唯一的值分别刷新1,300,000+像素。在具有四个处理器和8 GB内存的计算机上,这每帧花费500毫秒。我怀疑我在下面没有正确使用BufferedImage,并且我真的很想了解其他用于优化下面代码的帧间,体系结构级技术,而与最终将用于计算每个像素内像素值的算法无关-帧。您的代码示例和文章链接将不胜感激。

如何从逐帧(帧间)架构的角度而不是从帧内角度改进下面的代码?

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;

public class TestBuffer {
    private static void createAndShowUI() {
        TestPanel fastGraphicsPanel = new TestPanel();
        JFrame frame = new JFrame("This Needs A Faster Architecture!");
        frame.getContentPane().add(fastGraphicsPanel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setPreferredSize(new Dimension(800,600));
        frame.setResizable(true);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
    public static void main(String[] args) {java.awt.EventQueue.invokeLater(new Runnable() {
    public void run() {createAndShowUI();}});}
}

@SuppressWarnings("serial")
class TestPanel extends JPanel {
    int w, h;
    private static int WIDTH = 700;
    private static int HEIGHT = 500;
    private static final Color BACKGROUND_COLOR = Color.white;
    private BufferedImage bImg;
    private Color color = Color.black;

    public TestPanel() {
        bImg =  new BufferedImage(WIDTH, HEIGHT,BufferedImage.TYPE_INT_RGB);
        Graphics g = bImg.getGraphics();
        g.setColor(BACKGROUND_COLOR);
        g.fillRect(0, 0, WIDTH, HEIGHT);

        Timer myTimer = new Timer(10, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if(w!=0&&h!=0){
                    if(WIDTH!=w&&HEIGHT!=h){
                        WIDTH = w; HEIGHT = h;
                        bImg =  new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
                    }
                }
                repaint();
            }
        });
        myTimer.setInitialDelay(0);
        myTimer.setRepeats(true);
        myTimer.setCoalesce(true);
        myTimer.start();
        g.dispose();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        w = getWidth();
        h = getHeight();
//      System.out.println("w, h are: "+w+", "+h);
        long startTime = System.currentTimeMillis();
        g.drawImage(bImg, 0, 0, null);
        long endDrawImageTime = System.currentTimeMillis();
        Graphics2D g2 = (Graphics2D) g;
        drawRandomScreen(g2);
        long endDrawScreenTime = System.currentTimeMillis();
        long stopTime = System.currentTimeMillis();
        long drawImageTime = endDrawImageTime - startTime;
        long drawScreenTime = endDrawScreenTime - endDrawImageTime;
        long elapsedTime = stopTime - startTime;
        System.out.println(drawImageTime+", "+drawScreenTime+", "+elapsedTime);
    }

    private void drawRandomScreen(Graphics2D g2) {
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        for(int i=0;i<WIDTH;i++){
            for(int j=0;j<HEIGHT;j++){
                    color = new Color((int) (Math.random() * 255),(int) (Math.random() * 255),(int) (Math.random() * 255));
                    g2.setColor(color);
                    g2.drawLine(i, j, i, j);
            }
        }
    }
}

最佳答案

而不是通过Graphics2D进行交互,您应该直接与图像数据进行交互。这是我的代码,笔记本电脑可以20帧/秒(全屏)的速度运行

 @SuppressWarnings("serial")
class TestPanel extends JPanel {
    int w, h;
    private static int WIDTH = 700;
    private static int HEIGHT = 500;
    private static final Color BACKGROUND_COLOR = Color.white;
    private BufferedImage bImg;
    private Color color = Color.black;

    public TestPanel() {
        bImg =  new BufferedImage(WIDTH, HEIGHT,BufferedImage.TYPE_INT_RGB);
        Graphics g = bImg.getGraphics();
        g.setColor(BACKGROUND_COLOR);
        g.fillRect(0, 0, WIDTH, HEIGHT);

        Timer myTimer = new Timer(10, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if(w!=0&&h!=0){
                    if(WIDTH!=w&&HEIGHT!=h){
                        WIDTH = w; HEIGHT = h;
                        System.out.println("create");
                        bImg =  new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
                    }
                }
                repaint();
            }
        });
        myTimer.setInitialDelay(0);
        myTimer.setRepeats(true);
        myTimer.setCoalesce(true);
        myTimer.start();
        g.dispose();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        w = getWidth();
        h = getHeight();
//      System.out.println("w, h are: "+w+", "+h);
        long startTime = System.currentTimeMillis();
        long endDrawImageTime = System.currentTimeMillis();
//        Graphics2D g2 = (Graphics2D) g;
        drawRandomScreen(bImg);
        g.drawImage(bImg, 0, 0, null);
        long endDrawScreenTime = System.currentTimeMillis();
        long stopTime = System.currentTimeMillis();
        long drawImageTime = endDrawImageTime - startTime;
        long drawScreenTime = endDrawScreenTime - endDrawImageTime;
        long elapsedTime = stopTime - startTime;
        System.out.println(drawImageTime+", "+drawScreenTime+", "+elapsedTime);
    }

    private void drawRandomScreen(BufferedImage image) {

        final int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
        final int width = image.getWidth();
        final int height = image.getHeight();

        long startTime = System.currentTimeMillis();
//        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
//                RenderingHints.VALUE_ANTIALIAS_ON);
        Random r = new Random();
        for(int i=0;i<width;i++){
            for(int j=0;j<height;j++){
                    color = new Color(r.nextInt(255),r.nextInt(255),r.nextInt(255));
                    int pos = j*width+i;
                    pixels[pos] = color.hashCode();

            }
        }
        long stopTime = System.currentTimeMillis();
        System.out.println("time "+(stopTime-startTime));
    }
}

07-26 03:09