Graphics acceleration in java

  • #1
I have made a java code which displays a blue sphere and lets 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...
 

Answers and Replies

  • #2
35,062
6,794
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
AlephZero
Science Advisor
Homework Helper
6,994
293
Java has a "double buffering" option that lets 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
AlephZero
Science Advisor
Homework Helper
6,994
293
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
12,838
6,721
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 thats why gamers like to have high performance graphics card with their own built-in graphics cpu and games that support it.
 
  • #7
703
13
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
chiro
Science Advisor
4,790
132
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.
 

Related Threads on Graphics acceleration in java

  • Last Post
Replies
6
Views
3K
Replies
2
Views
2K
  • Last Post
Replies
6
Views
2K
  • Last Post
Replies
3
Views
2K
  • Last Post
2
Replies
48
Views
2K
Replies
16
Views
9K
  • Last Post
Replies
2
Views
3K
  • Last Post
Replies
10
Views
1K
  • Last Post
Replies
3
Views
751
Top