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

Click For Summary

Discussion Overview

The discussion revolves around optimizing graphics acceleration in a Java application that displays a 3D sphere controlled by mouse movement. Participants explore various methods to improve the performance of the rendering process, addressing issues related to slow updates of the image when the mouse is moved quickly.

Discussion Character

  • Technical explanation
  • Debate/contested
  • Mathematical reasoning

Main Points Raised

  • One participant shares a Java code that displays a sphere and seeks help to improve the update speed of the image when dragging the mouse.
  • Another participant suggests that Java may not be the best choice for frequently updated graphics due to its interpreted nature, recommending compiled languages instead.
  • A different participant mentions Java's "double buffering" option to reduce flickering but notes it may not enhance speed.
  • Suggestions are made to optimize the color calculation function by rearranging conditions and avoiding unnecessary recalculations of trigonometric functions for each pixel.
  • One participant reports significant improvements in update times after implementing suggested optimizations, reducing the time from 500-600 ms to 125 ms.
  • Another participant emphasizes that Java's performance has improved due to JVM and hotspot compiling, arguing that it can be suitable for real-time applications.
  • There is a request for the updated code after optimizations were made.
  • The participant who optimized the code shares the revised version, incorporating the discussed improvements.

Areas of Agreement / Disagreement

Participants generally agree on the potential for optimization within the Java code, but there is a lack of consensus on the suitability of Java for high-performance graphics compared to other languages.

Contextual Notes

Some limitations in the discussion include the dependence on specific implementations of Java graphics and the potential for further optimizations that have not been explored in depth.

Who May Find This Useful

Java developers interested in graphics programming, particularly those facing performance issues in real-time rendering applications.

matiasmorant
Messages
38
Reaction score
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
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.
 
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(...)
    }
}
 
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!
 
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...
 
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.
 
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?
 
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);
}

}
 
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.
 

Similar threads

  • · Replies 1 ·
Replies
1
Views
1K
  • · Replies 1 ·
Replies
1
Views
2K
  • · Replies 2 ·
Replies
2
Views
2K
  • · Replies 1 ·
Replies
1
Views
3K
  • · Replies 1 ·
Replies
1
Views
2K
  • · Replies 4 ·
Replies
4
Views
6K
  • · Replies 3 ·
Replies
3
Views
3K
  • · Replies 5 ·
Replies
5
Views
3K
  • · Replies 1 ·
Replies
1
Views
2K
  • · Replies 1 ·
Replies
1
Views
2K