Optimizing Graphics Acceleration in Java: A Solution to Slow Mouse Motion Update

In summary, the conversation discusses methods to improve the speed of a Java code that displays a 3D sphere with a controllable light source. The code uses a BufferedImage and a MouseMotionListener to update the image as the mouse is moved. Possible solutions to improve the speed include using double buffering, optimizing the color() method, and limiting the number of calls to color(). The conversation also mentions that Java may not be the best choice for graphics programming and that it is important to pay attention to detail when programming.
  • #1
matiasmorant
39
0
I have made a java code which displays a blue sphere and let's you control with the mouse where its illumination comes from. (its actually a circle and some parts are painted white/blue/black depending on the mouse position to make it look 3D)

here is the code


import javax.swing.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.imageio.*;

public class esfera extends JFrame{

double azimuth=3*Math.PI/4, inclination=Math.PI/4; //angle coordinates for the 'light source'

private BufferedImage image = new BufferedImage(800,800,BufferedImage.TYPE_INT_RGB); //the image storing the sphere drawing

public esfera(){ //initializer adding a listener to mouse motion
addMouseMotionListener(new MouseMotionAdapter(){
public void mouseDragged(MouseEvent e){
azimuth=((800-e.getX())/800.00)*Math.PI;
inclination=(e.getY()/800.00)*Math.PI;
repaint();
}
});}

public void paint(Graphics g){ //does the whole painting

g.drawImage(image,0,0,null); //paint the current image to the frame

for(int i=0;i<800;i++){ //make next image, pixel by pixel
for(int j=0;j<800;j++){
image.setRGB(i,j,color((i-400)/200.00,(400-j)/200.00));
}
}
}

public int color(double x, double y){ //this is what color each pixel should be painted in order to make the picture look like a sphere
double clr;
double z = Math.sqrt(1-(x*x+y*y));
double angle = Math.acos(Math.cos(inclination)*y+Math.sin(inclination)*(Math.sin(azimuth)*z+Math.cos(azimuth)*x));

if(x*x+y*y>1) clr=0;
else if (angle>Math.PI/2) clr=0;
else if (angle>Math.PI/4)clr=255*(2-angle/(Math.PI/4));
else{ int white =((int)(255*(1-angle/(Math.PI/4)))<<8)+((int)(255*(1-angle/(Math.PI/4)))<<16);
clr=white+255;}

return (int)clr;

}

public static void main(String[] args){ //the main method of course

esfera frame = new esfera();
frame.setSize(800,800);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}

}

it works ok. the only problem is that when you move the mouse it takes too long to update the screen with the next picture.(so the 'light source' seems to be jumping from one place to another if you move the mouse too fast)


the question is: how can I fix this problem?


i have been reading about VolatileImage but it seems that you can't write a VolatileImage pixel by pixel, so it's not what i need.

i have also read about BufferStrategy, but I'm not sure if it could help me or not, (didn't completely understand how to use it neither)


could you help me please? I've been trying to solve it all day...
 
Technology news on Phys.org
  • #2
Java is probably not the best choice for drawing figures on the screen that need to be frequently updated. The reason for this is that your code gets compiled into Java byte codes that are then translated into machine instructions at run time. For graphics programming, compiled languages rather than interpreted languages (like Java) are usually preferred.

The way programmers did things in the "old days" was to work with several screen buffers that they would swap into and out of screen memory. While one buffer was being updated, another screen buffer that was ready to be viewed was swapped into memory. I don't know if you could do this in Java.
 
  • #3
Java has a "double buffering" option that let's you create the next image completely before you display it. That will get rid of any "flickering" as you move the images but it won't make the app run faster. http://docs.oracle.com/javase/tutorial/extra/fullscreen/doublebuf.html

You could do some optimisation on color() and the way you call image.setRGB().

A simple speed-up for color() would be to do the test
Code:
if(x*x+y*y>1) clr=0;
first, before you calculate the expensive square roots and trig functions.
Also asimuth and incliation don't change, so you don't need to recalculate the same sines and cosines 640,000 times for each pixel of the image

If that isn't enough, you could limit the number of calls to color().

Apparently everything outside of the sphere is black, so you could set the complete image to black with one call, not pixel by pixel. Then you could limit the for loops to cover the image. Something like
Code:
Find imin and imax that cover the image
for i  = imin to imax {
    find jmin and jmax that cover line i of the image
    for j = jmin to jmax {
       color(...)
    }
}
 
  • #4
it originally took 500-600-ms to update the image
doing the if(x*x+y*y>1) clr=0; test first, it only took 300-250ms
avoiding the recalculation of asimuth and incliation, 200-225 ms

the image is initializated to black by default, so recalculating pixel by pixel only the smallest square fitting the sphere, it takes 125 ms to update

:O thanks a lot!
 
  • #5
matiasmorant said:
it originally took 500-600-ms to update the image
doing the if(x*x+y*y>1) clr=0; test first, it only took 300-250ms
avoiding the recalculation of asimuth and incliation, 200-225 ms

the image is initializated to black by default, so recalculating pixel by pixel only the smallest square fitting the sphere, it takes 125 ms to update

:O thanks a lot!

Take-home message: good programming is about attention to detail. :smile:

I bet you can make it run quite a bit faster than 8 frames per seond, if you do some more thinking. Hint: there seems to be lot of converting real values to integers and back again...
 
  • #6
also don't underestimate java as far as speed goes as its JVM and hotspot compiling have really sped things up considerably though it will never match a finally crafted C or asm program.

we use Java a lot for our realtime charting and displays and it works just fine. Ray tracing is very cpu/graphics intense and that's why gamers like to have high performance graphics card with their own built-in graphics cpu and games that support it.
 
  • #7
matiasmorant said:
it originally took 500-600-ms to update the image
doing the if(x*x+y*y>1) clr=0; test first, it only took 300-250ms
avoiding the recalculation of asimuth and incliation, 200-225 ms

the image is initializated to black by default, so recalculating pixel by pixel only the smallest square fitting the sphere, it takes 125 ms to update

:O thanks a lot!

Can you post your new code?
 
  • #8
here's the new code :)

import javax.swing.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.imageio.*;

public class esfera extends JFrame{

double azimuth=3*Math.PI/4, inclination=Math.PI/4; //angle coordinates for the 'light source'
double cosAzimuth=Math.cos(azimuth) ,sinAzimuth=Math.sin(azimuth), cosInclination=Math.cos(inclination),sinInclination=Math.sin(inclination);

private BufferedImage image = new BufferedImage(800,800,BufferedImage.TYPE_INT_RGB); //the image storing the sphere drawing

public esfera(){ //initializer adding a listener to mouse motion
addMouseMotionListener(new MouseMotionAdapter(){
public void mouseDragged(MouseEvent e){
azimuth=((800-e.getX())/800.00)*Math.PI;
inclination=(e.getY()/800.00)*Math.PI;
cosAzimuth=Math.cos(azimuth);
sinAzimuth=Math.sin(azimuth);
cosInclination=Math.cos(inclination);
sinInclination=Math.sin(inclination);
repaint();
}
});}

public void paint(Graphics g){ //does the whole painting

g.drawImage(image,0,0,null); //paint the current image to the frame

for(int i=200;i<600;i++){ //make next image, pixel by pixel
for(int j=200;j<600;j++){
image.setRGB(i,j,color((i-400)/200.00,(400-j)/200.00));
}
}
}

public int color(double x, double y){ //this is what color each pixel should be painted in order to make the picture look like a sphere
double clr;

if(x*x+y*y>1) clr=0;
else {
double z = Math.sqrt(1-(x*x+y*y));
double angle = Math.acos(cosInclination*y+sinInclination*(sinAzimuth*z+cosAzimuth*x));

if (angle>Math.PI/2) clr=0;
else if (angle>Math.PI/4)clr=255*(2-angle/(Math.PI/4));
else{ int white =((int)(255*(1-angle/(Math.PI/4)))<<8)+((int)(255*(1-angle/(Math.PI/4)))<<16);
clr=white+255;}

}

return (int)clr;

}

public static void main(String[] args){ //the main method of course

esfera frame = new esfera();
frame.setSize(800,800);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}

}
 
  • #9
I'm surprised there isn't some standard library that has an OpenGL/DirectX type implementation to allow hardware-accelerated 2D and 3D rendering.

Also back in the old days instead of calculating trig functions directly, what we used to do is pre-calculate these into an array and use these values as "look-up" values. The arrays themselves were called "look-up tables". You might be interested in using these, especially in the kind of VM environment that Java is.
 

What is graphics acceleration in Java?

Graphics acceleration in Java refers to the process of using hardware-accelerated graphics to improve the performance and quality of graphics in Java applications. It involves utilizing the capabilities of a computer's graphics processing unit (GPU) to handle complex graphics tasks, resulting in smoother and more efficient rendering of images, animations, and other visual elements.

How does graphics acceleration work in Java?

In Java, graphics acceleration works by offloading graphics processing tasks from the central processing unit (CPU) to the GPU. This is achieved through the use of specialized programming interfaces, such as OpenGL and DirectX, which are supported by most modern GPUs. By leveraging the parallel processing power of the GPU, graphics acceleration can significantly improve the performance and responsiveness of Java applications that require intensive graphics processing.

What are the benefits of using graphics acceleration in Java?

The main benefit of graphics acceleration in Java is improved performance. By utilizing the capabilities of the GPU, graphics acceleration can significantly reduce the workload on the CPU and produce smoother and more responsive graphics. This can be especially beneficial for applications that require high-quality graphics, such as video games or multimedia applications.

Are there any limitations to graphics acceleration in Java?

While graphics acceleration can greatly enhance the performance of graphics in Java applications, it does have some limitations. For example, not all computers may have a dedicated GPU capable of supporting graphics acceleration, which could limit the potential benefits. Additionally, support for graphics acceleration may also vary depending on the operating system and the version of Java being used.

How can I enable graphics acceleration in my Java application?

In most cases, graphics acceleration is enabled by default in Java applications. However, if you want to ensure that graphics acceleration is being used, you can check the graphics settings in your application or use a tool like Java VisualVM to monitor the performance of your application. If graphics acceleration is not enabled, you may need to update your graphics drivers or check your application's settings to enable it.

Similar threads

  • Programming and Computer Science
Replies
2
Views
1K
  • Programming and Computer Science
Replies
1
Views
2K
  • Programming and Computer Science
Replies
1
Views
1K
  • Programming and Computer Science
Replies
4
Views
5K
  • Engineering and Comp Sci Homework Help
Replies
3
Views
2K
  • Engineering and Comp Sci Homework Help
Replies
5
Views
2K
  • Engineering and Comp Sci Homework Help
Replies
2
Views
2K
  • Programming and Computer Science
Replies
1
Views
2K
Back
Top