更改绘画方法导致纹理算法 运行 真的很慢吗?

Change to painting method caused texturing algorithm to run really slowly?

我正在制作一个 3D 游戏,我以前绘制到屏幕的方式是添加一个包含“游戏屏幕”的 JLabel 作为 BufferedImageJPanel,并使用 BufferedImage.setRGB() 更改单个像素。但是,我决定直接使用 PaintComponent() 切换到 JPanel 绘图。在进行切换并且不触及纹理算法之后(除了将所需像素颜色添加到屏幕缓冲区而不是直接更改颜色之类的更改之外,所以如果有的话,它应该更快),它现在运行得非常慢(大约需要0.3 秒,有时甚至更多来完成纹理算法,其他一切几乎都是即时的)。无论如何要修复它?另外,如果您发现代码有其他问题,请随时告诉我。

    public CanvasPanel(JFrame frame, int width, int height)
    {
        this.frame = frame;
        setPreferredSize(new Dimension(width, height));
        setSize(width, height);
        trianglesToDraw = new ArrayList<>();
        //add(label);
        keysPressed = new boolean[9];
        addKeyListener(new KeyListener()
        {
            @Override
            public void keyTyped(KeyEvent e)
            {
            
            }
            
            @Override
            public void keyPressed(KeyEvent e)
            {
                int key = e.getKeyCode();
                
                if (key == KeyEvent.VK_W)
                {
                    keysPressed[0] = true;
                }
                else if (key == KeyEvent.VK_A)
                {
                    keysPressed[1] = true;
                }
                else if (key == KeyEvent.VK_S)
                {
                    keysPressed[2] = true;
                }
                else if (key == KeyEvent.VK_D)
                {
                    keysPressed[3] = true;
                }
                else if (key == KeyEvent.VK_SPACE)
                {
                    keysPressed[4] = true;
                }
            }
            
            @Override
            public void keyReleased(KeyEvent e)
            {
                int key = e.getKeyCode();
                
                if (key == KeyEvent.VK_W)
                {
                    keysPressed[0] = false;
                }
                else if (key == KeyEvent.VK_A)
                {
                    keysPressed[1] = false;
                }
                else if (key == KeyEvent.VK_S)
                {
                    keysPressed[2] = false;
                }
                else if (key == KeyEvent.VK_D)
                {
                    keysPressed[3] = false;
                }
                else if (key == KeyEvent.VK_SPACE)
                {
                    keysPressed[4] = false;
                }
            }
        });
        objects = new ArrayList<>();
        Hyperrectangle ground = new Hyperrectangle(new Vector(-10.0f, -10.0f, -10.0f), new Vector(10.0f, 10.0f, 10.0f), true);
        objects.add(ground);
        if (objects.get(0).textured)
        {
            try
            {
                objects.get(0).texture = ImageIO.read(new File(texturePath));
                crosshair = ImageIO.read(new File("src/res/crosshair.png"));
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }

        float aspectRatio = (float) getHeight() / (float) getWidth();
        float zNear = 0.1f;
        float zFar = 1000.0f;
        float fov = 90.0f;
        projectionMatrix = MathUtils.makeProjectionMatrix(fov, aspectRatio, zNear, zFar);
        depthBuffer = new float[getWidth()][getHeight()];
        screenBuffer = new int[getWidth()][getHeight()];
        try
        {
            robot = new Robot();
        }
        catch (AWTException e)
        {
            e.printStackTrace();
        }
        
        BufferedImage cursorImg = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
        Cursor blankCursor = Toolkit.getDefaultToolkit().createCustomCursor(cursorImg, new Point(0, 0), "blank cursor");
        frame.getContentPane().setCursor(blankCursor);
    
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        int centerX = (int) screenSize.getWidth() / 2;
        int centerY = (int) screenSize.getHeight() / 2;
        robot.mouseMove(centerX, centerY);
        
        for (int i = 0; i < getWidth(); i++)
        {
            for (int j = 0; j < getHeight(); j++)
            {
                depthBuffer[i][j] = 0.0f;
                screenBuffer[i][j] = 0;
            }
        }
        
        Timer timer = new Timer(30, e -> newFrame(projectionMatrix));
        timer.start();
    }

    private void newFrame(float[][] projectionMatrix)
    {
        trianglesToDraw.clear();
        for (int i = 0; i < getWidth(); i++)
        {
            for (int j = 0; j < getHeight(); j++)
            {
                depthBuffer[i][j] = 0.0f;
                screenBuffer[i][j] = 0;
            }
        }
        
        Vector up = new Vector(0.0f, 1.0f, 0.0f);
        float cameraSpeed = 0.5f;
        Vector target = MathUtils.multiply(camera.lookDirection, cameraSpeed);
        target.y = 0.0f;
    
        Point mousePosition = MouseInfo.getPointerInfo().getLocation();
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        int centerX = (int) screenSize.getWidth() / 2;
        int centerY = (int) screenSize.getHeight() / 2;
        robot.mouseMove(centerX, centerY);
        float dx = mousePosition.x - centerX;
        float dy = mousePosition.y - centerY;
    
        float newYaw = camera.yaw + cameraSpeed * dx;
        float newPitch = camera.pitch + cameraSpeed * dy;
        
        if (!Double.isNaN(dx))
        {
            camera.yaw = newYaw;
        }
        if (!Double.isNaN(dy))
        {
            if (newPitch < 180.0f && newPitch > -180.0f)
            {
                camera.pitch = newPitch;
            }
        }
        
        if (keysPressed[0]) // W, move forward
        {
            camera.origin.add(target);
        }
        if (keysPressed[1]) // A, strafe left
        {
            Vector right = MathUtils.cross(target, up);
            camera.origin.subtract(right);
        }
        if (keysPressed[2]) // S, move backward
        {
            camera.origin.subtract(target);
        }
        if (keysPressed[3]) // D, strafe right
        {
            Vector right = MathUtils.cross(target, up);
            camera.origin.add(right);
        }
        if (keysPressed[4]) // SPACE, teleport to origin
        {
            camera.origin = new Vector(0.0f);
        }
        
        float[][] xWorldRotationMatrix = MathUtils.makeXRotationMatrix(0.0f);
        float[][] yWorldRotationMatrix = MathUtils.makeYRotationMatrix(0.0f);
        float[][] zWorldRotationMatrix = MathUtils.makeZRotationMatrix(0.0f);
        float[][] worldRotationMatrix = MathUtils.multiply(MathUtils.multiply(yWorldRotationMatrix, xWorldRotationMatrix), zWorldRotationMatrix);
        float[][] translationMatrix = MathUtils.makeTranslationMatrix(0.0f, 0.0f, 20.0f);
        float[][] worldMatrix = MathUtils.multiply(worldRotationMatrix, translationMatrix);
        
        float[][] xCameraRotationMatrix = MathUtils.makeXRotationMatrix(camera.pitch);
        float[][] yCameraRotationMatrix = MathUtils.makeYRotationMatrix(camera.yaw);
        float[][] zCameraRotationMatrix = MathUtils.makeZRotationMatrix(0.0f);
        float[][] cameraRotationMatrix = MathUtils.multiply(MathUtils.multiply(yCameraRotationMatrix, xCameraRotationMatrix), zCameraRotationMatrix);
        
        Vector forward = new Vector(0.0f, 0.0f, 1.0f);
        camera.lookDirection = MathUtils.multiply(cameraRotationMatrix, forward);
        forward = MathUtils.add(camera.origin, camera.lookDirection);
        
        float[][] cameraMatrix = (MathUtils.inverseMatrix(camera.pointAt(forward, up)));
        
        for (GameObject object : objects)
        {
            for (Triangle triangle : object.triangles)
            {
                calculateTriangles(triangle, worldMatrix, projectionMatrix, cameraMatrix);
            }
        }
    
        for (Triangle t : trianglesToDraw)
        {
            t.draw(this, objects.get(0).texture);
        }
        
        repaint();
    }

    void draw(CanvasPanel viewport, BufferedImage texture)
    {
        int x1 = (int) this.points[0].x, x2 = (int) this.points[1].x, x3 = (int) this.points[2].x;
        int y1 = (int) this.points[0].y, y2 = (int) this.points[1].y, y3 = (int) this.points[2].y;
        float u1 = this.textureCoordinates[0].u, u2 = this.textureCoordinates[1].u, u3 = this.textureCoordinates[2].u;
        float v1 = this.textureCoordinates[0].v, v2 = this.textureCoordinates[1].v, v3 = this.textureCoordinates[2].v;
        float w1 = this.textureCoordinates[0].w, w2 = this.textureCoordinates[1].w, w3 = this.textureCoordinates[2].w;
        int temp1;
        float temp2;
        
        if (y2 < y1)
        {
            temp1 = y1;
            y1 = y2;
            y2 = temp1;
            
            temp1 = x1;
            x1 = x2;
            x2 = temp1;
            
            temp2 = u1;
            u1 = u2;
            u2 = temp2;
            
            temp2 = v1;
            v1 = v2;
            v2 = temp2;
            
            temp2 = w1;
            w1 = w2;
            w2 = temp2;
        }
        
        if (y3 < y1)
        {
            temp1 = y1;
            y1 = y3;
            y3 = temp1;
            
            temp1 = x1;
            x1 = x3;
            x3 = temp1;
            
            temp2 = u1;
            u1 = u3;
            u3 = temp2;
            
            temp2 = v1;
            v1 = v3;
            v3 = temp2;
            
            temp2 = w1;
            w1 = w3;
            w3 = temp2;
        }
        
        if (y3 < y2)
        {
            temp1 = y2;
            y2 = y3;
            y3 = temp1;
            
            temp1 = x2;
            x2 = x3;
            x3 = temp1;
            
            temp2 = u2;
            u2 = u3;
            u3 = temp2;
            
            temp2 = v2;
            v2 = v3;
            v3 = temp2;
            
            temp2 = w2;
            w2 = w3;
            w3 = temp2;
        }
        
        int dy1 = y2 - y1;
        int dx1 = x2 - x1;
        float du1 = u2 - u1;
        float dv1 = v2 - v1;
        float dw1 = w2 - w1;
        
        int dy2 = y3 - y1;
        int dx2 = x3 - x1;
        float dv2 = v3 - v1;
        float du2 = u3 - u1;
        float dw2 = w3 - w1;
        
        float uTexture, vTexture, wTexture;
        float dx1Step = 0, dx2Step = 0, du1Step = 0, du2Step = 0, dv1Step = 0, dv2Step = 0, dw1Step = 0, dw2Step = 0;

        if (dy1 != 0)
        {
            dx1Step = dx1 / (float) Math.abs(dy1);
        }
        if (dy2 != 0)
        {
            dx2Step = dx2 / (float) Math.abs(dy2);
        }
        if (dy1 != 0)
        {
            du1Step = du1 / (float) Math.abs(dy1);
        }
        if (dy2 != 0)
        {
            du2Step = du2 / (float) Math.abs(dy2);
        }
        if (dy1 != 0)
        {
            dv1Step = dv1 / (float) Math.abs(dy1);
        }
        if (dy2 != 0)
        {
            dv2Step = dv2 / (float) Math.abs(dy2);
        }
        if (dy1 != 0)
        {
            dw1Step = dw1 / (float) Math.abs(dy1);
        }
        if (dy2 != 0)
        {
            dw2Step = dw2 / (float) Math.abs(dy2);
        }
    
        if (dy1 != 0)
        {
            for (int y = y1; y <= y2; y++)
            {
                int xStart = (int) (x1 + (y - y1) * dx1Step);
                int xEnd = (int) (x1 + (y - y1) * dx2Step);
                
                float uStart = u1 + (y - y1) * du1Step;
                float uEnd = u1 + (y - y1) * du2Step;
                
                float vStart = v1 + (y - y1) * dv1Step;
                float vEnd = v1 + (y - y1) * dv2Step;
                
                float wStart = w1 + (y - y1) * dw1Step;
                float wEnd = w1 + (y - y1) * dw2Step;
                
                if (xStart > xEnd)
                {
                    temp1 = xStart;
                    xStart = xEnd;
                    xEnd = temp1;
                    
                    temp2 = uStart;
                    uStart = uEnd;
                    uEnd = temp2;
                    
                    temp2 = vStart;
                    vStart = vEnd;
                    vEnd = temp2;
                    
                    temp2 = wStart;
                    wStart = wEnd;
                    wEnd = temp2;
                }
                
                float tStep = 1.0f / (xEnd - xStart);
                float t = 0.0f;
    
                for (int x = xStart; x < xEnd; x++)
                {
                    uTexture = (1.0f - t) * uStart + t * uEnd;
                    vTexture = (1.0f - t) * vStart + t * vEnd;
                    wTexture = (1.0f - t) * wStart + t * wEnd;
                    
                    if (uTexture / wTexture >= 1 || vTexture / wTexture >= 1) // Temporary fix
                    {
                        uTexture = 0.0f;
                        vTexture = 0.0f;
                    }

                    int pixelColor;

                    if (textured)
                    {
                        int uTextureCoordinates = (int) ((uTexture / wTexture) * texture.getWidth());
                        int vTextureCoordinates = (int) ((vTexture / wTexture) * texture.getHeight());
                        try
                        {
                            pixelColor = texture.getRGB(uTextureCoordinates, vTextureCoordinates);
                        }
                        catch (ArrayIndexOutOfBoundsException e)
                        {
                            pixelColor = Color.black.getRGB();
                        }
                    }
                    else
                    {
                        pixelColor = color.getRGB();
                    }

                    if (wTexture > viewport.depthBuffer[x][y])
                    {
                        viewport.screenBuffer[x][y] = pixelColor;
                        viewport.depthBuffer[x][y] = wTexture;
                    }
                    
                    t += tStep;
                }
            }
        }
        
        
        dy1 = y3 - y2;
        dx1 = x3 - x2;
        du1 = u3 - u2;
        dv1 = v3 - v2;
        dw1 = w3 - w2;
        
        if (dy1 != 0)
        {
            dx1Step = dx1 / (float) Math.abs(dy1);
        }
        if (dy2 != 0)
        {
            dx2Step = dx2 / (float) Math.abs(dy2);
        }
        if (dy1 != 0)
        {
            du1Step = du1 / (float) Math.abs(dy1);
        }
        if (dy1 != 0)
        {
            dv1Step = dv1 / (float) Math.abs(dy1);
        }
        if (dy1 != 0)
        {
            dw1Step = dw1 / (float) Math.abs(dy1);
        }
        
        if (dy1 != 0)
        {
            for (int y = y2; y <= y3; y++)
            {
                int xStart = (int) (x2 + (y - y2) * dx1Step);
                int xEnd = (int) (x1 + (y - y1) * dx2Step);
                
                float uStart = u2 + (y - y2) * du1Step;
                float uEnd = u1 + (y - y1) * du2Step;
                
                float vStart = v2 + (y - y2) * dv1Step;
                float vEnd = v1 + (y - y1) * dv2Step;
                
                float wStart = w2 + (y - y2) * dw1Step;
                float wEnd = w1 + (y - y1) * dw2Step;
                
                if (xStart > xEnd)
                {
                    temp1 = xStart;
                    xStart = xEnd;
                    xEnd = temp1;
                    
                    temp2 = uStart;
                    uStart = uEnd;
                    uEnd = temp2;
                    
                    temp2 = vStart;
                    vStart = vEnd;
                    vEnd = temp2;
                    
                    temp2 = wStart;
                    wStart = wEnd;
                    wEnd = temp2;
                }
                
                float tStep = 1.0f / (xEnd - xStart);
                float t = 0.0f;
                
                for (int x = xStart; x < xEnd; x++)
                {
                    uTexture = (1.0f - t) * uStart + t * uEnd;
                    vTexture = (1.0f - t) * vStart + t * vEnd;
                    wTexture = (1.0f - t) * wStart + t * wEnd;
    
                    if (uTexture / wTexture >= 1 || vTexture / wTexture >= 1) // Temporary fix
                    {
                        uTexture = 0.0f;
                        vTexture = 0.0f;
                    }
                    
                    int pixelColor;
                    
                    if (textured)
                    {
                        int uTextureCoordinates = (int) ((uTexture / wTexture) * texture.getWidth());
                        int vTextureCoordinates = (int) ((vTexture / wTexture) * texture.getHeight());
                        try
                        {
                            pixelColor = texture.getRGB(uTextureCoordinates, vTextureCoordinates);
                        }
                        catch (ArrayIndexOutOfBoundsException e)
                        {
                            pixelColor = Color.black.getRGB();
                        }
                    }
                    else
                    {
                        pixelColor = color.getRGB();
                    }
                    
                    if (wTexture > viewport.depthBuffer[x][y])
                    {
                        viewport.screenBuffer[x][y] = pixelColor;
                        viewport.depthBuffer[x][y] = wTexture;
                    }
    
                    t += tStep;
                }
            }
        }
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        
        for (int i = 0; i < getWidth(); i++)
        {
            for (int j = 0; j < getHeight(); j++)
            {
                g.setColor(getColorFromRGBCode(screenBuffer[i][j]));
                g.drawLine(i, j, i, j);
            }
        }
        
        g.drawImage(crosshair, getWidth() / 2 - crosshair.getWidth() / 2, getHeight() / 2 - crosshair.getHeight() / 2, null);
    }

嗯,事实证明使用 BufferedImage 更好,所以我将屏幕缓冲区更改为 1,它再次运行良好。