java directdraw,在没有Opengl或Direct3d管道的情况下使用Java2d进行平滑绘制?

本文探讨了在禁用Java 2D的Direct3D和OpenGL管道时如何实现平滑的图形运动。通过提供一个简单的代码示例,展示了即使在这些硬件加速选项不可用的情况下,如何改进帧率和更新机制来减少画面撕裂和提高动画流畅性。主要优化策略包括:确保在事件分派线程中更新UI,避免过度绘制和在动画循环中适当睡眠。
摘要由CSDN通过智能技术生成

I can't figure out a way to get smooth movement or animation of anything using Java2d when the opengl and direct3d pipelines are disabled (by invoking the vm with -Dsun.java2d.d3d=false and -Dsun.java2d.opengl=false)

The quick and dirty code below demonstrates my problem. It draws a box that moves across the screen. The box location is updated about 60 times per second and the screen is redrawn as many times as possible. It uses the BufferStrategy class to implement double buffering; the flip is done at "bs.show();"

Code(press escape to quit):

import java.awt.Color;

import java.awt.Frame;

import java.awt.Graphics;

import java.awt.GraphicsConfiguration;

import java.awt.GraphicsDevice;

import java.awt.GraphicsEnvironment;

import java.awt.Rectangle;

import java.awt.event.KeyAdapter;

import java.awt.event.KeyEvent;

import java.awt.image.BufferStrategy;

public class FluidMovement {

private static volatile boolean running = true;

private static final int WIDTH = 500;

private static final int HEIGHT = 350;

public static void main(String[] args) {

GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();

GraphicsDevice gd = ge.getDefaultScreenDevice();

GraphicsConfiguration gc = gd.getDefaultConfiguration();

Frame frame = new Frame(gc);

frame.setIgnoreRepaint(true);

frame.setUndecorated(true);

frame.addKeyListener(new KeyAdapter() {

@Override public void keyPressed(KeyEvent e) {

if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {

running = false;

}

}

});

frame.setSize(WIDTH, HEIGHT);

frame.setVisible(true);

frame.createBufferStrategy(2);

BufferStrategy bs = frame.getBufferStrategy();

long nextTick = System.nanoTime();

class Rect {

int dx = 2, dy = 1, x = 0, y = 0;

}

Rect rect = new Rect();

Graphics g;

while (running) {

if (System.nanoTime() > nextTick) {

rect.x = (rect.x + rect.dx) % WIDTH;

rect.y = (rect.y + rect.dy) % HEIGHT;

nextTick += 1000000000 / 60;

}

g = bs.getDrawGraphics();

g.setColor(Color.BLACK);

g.fillRect(0, 0, WIDTH, HEIGHT);

g.setColor(Color.WHITE);

g.fillRect(rect.x, rect.y, 10, 10);

g.dispose();

bs.show();

}

bs.dispose();

frame.dispose();

}

}

When I execute this code normally with "java FluidMovement", it runs smooth as silk (besides the occasional tearing) because the jvm makes use of the direct3d/directdraw pipeline. When i execute this code with "java -Dsun.java2d.d3d=false -Dsun.java2d.opengl=false FluidMovement" it is terribly choppy.

I can't make the assumption that the direct3d or opengl pipeline is used. The pipelines don't work with 2 of the 3 machines I have tried it on; it only worked on a machine with dedicated graphics running Windows 7. Is there anyway I can make the box move smoothly or should i resort to using some kind of library with low level access like JOGL?

Notes:

Frame rate is not the issue. In both cases (pipelines enabled and disabled), the application runs well over 300 fps. I forced vsync off when the pipelines are enabled.

I've tried Toolkit.getDefaultToolkit().sync()

I've tried many different types of loops, but the movement is never truly smooth. Even with a fixed framerate the same choppiness is exhibited.

I've tried running the frame in full-screen exclusive mode.

I've tried using 3 or even 4 buffers.

解决方案

A number of things jump out at me and scare me...

You're not honoring the thread/Swing contract. All updates to the UI MUST be made from with the Event Dispatching Thread. All long running and blocking code should be executed in a background thread.

Your "animation loop" is sucking up a lot of CPU time doing nothing. The thread should be sleeping between cycles (or at the very least, should only paint when something has changed), this should reduce the over all load on the system.

I tried a few solutions.

While I didn't have "significant" issues, these are really simple examples, I did generally get better performance with the default JVM options.

Buffering strategy

This is basically what you had, begin nice to the EDT and using the buffer strategy your were using

public class SimpleAnimationTest {

private boolean running = true;

private Rectangle box = new Rectangle(0, 90, 10, 10);

private int dx = 4;

protected static final int WIDTH = 200;

protected static final int HEIGHT = 200;

public static void main(String[] args) {

new SimpleAnimationTest();

}

public SimpleAnimationTest() {

EventQueue.invokeLater(new Runnable() {

@Override

public void run() {

try {

UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {

}

JFrame frame = new JFrame();

frame.setIgnoreRepaint(true);

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

frame.setLayout(new BorderLayout());

frame.setSize(WIDTH, HEIGHT);

frame.setLocationRelativeTo(null);

frame.setVisible(true);

frame.createBufferStrategy(2);

final BufferStrategy bs = frame.getBufferStrategy();

new Thread(new Runnable() {

@Override

public void run() {

long tock = 1000 / 60;

while (running) {

box.x += dx;

if (box.x + box.width > WIDTH) {

box.x = WIDTH - box.width;

dx *= -1;

} else if (box.x < 0) {

box.x = 0;

dx *= -1;

}

Graphics2D g = (Graphics2D) bs.getDrawGraphics();

g.setColor(Color.BLACK);

g.fillRect(0, 0, WIDTH, HEIGHT);

g.setColor(Color.WHITE);

g.fill(box);

g.dispose();

bs.show();

try {

Thread.sleep(tock);

} catch (InterruptedException ex) {

}

}

bs.dispose();

}

}).start();

}

});

}

}

Double Buffered Swing Components

public class SimpleAnimationTest {

private Rectangle box = new Rectangle(0, 90, 10, 10);

private int dx = 4;

public static void main(String[] args) {

new SimpleAnimationTest();

}

public SimpleAnimationTest() {

EventQueue.invokeLater(new Runnable() {

@Override

public void run() {

try {

UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {

}

JFrame frame = new JFrame();

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

frame.setLayout(new BorderLayout());

frame.add(new SimplePane());

frame.pack();

frame.setLocationRelativeTo(null);

frame.setVisible(true);

}

});

}

public class SimplePane extends JPanel {

public SimplePane() {

setDoubleBuffered(true);

Timer timer = new Timer(1000 / 300, new ActionListener() {

@Override

public void actionPerformed(ActionEvent e) {

box.x += dx;

if (box.x + box.width > getWidth()) {

box.x = getWidth() - box.width;

dx *= -1;

} else if (box.x < 0) {

box.x = 0;

dx *= -1;

}

repaint();

}

});

timer.setRepeats(true);

timer.setCoalesce(true);

timer.start();

}

@Override

protected void paintComponent(Graphics g) {

Graphics2D g2d = (Graphics2D) g.create();

super.paintComponent(g2d);

box.y = (getHeight() - box.height) / 2;

g2d.setColor(Color.RED);

g2d.fill(box);

g2d.dispose();

}

@Override

public Dimension getPreferredSize() {

return new Dimension(200, 200);

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值