Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm trying to make a distortion effect for a space game. The idea is that the effect has a central point, and all nearby objects appear to swirl into that point. I've made a preliminary version and it looks like this:

Screenshot of the effect

I'm pretty much satisfied with this effect, but the problem is that it takes far too long -- about 150 ms -- and I need to render it every second or third frame, at least. How can I achieve a similar effect efficiently in Java2D? (If you're interested, my source code is here: http://pastebin.com/1W9RrA44)

share|improve this question

2 Answers 2

up vote 4 down vote accepted

Kevin gave you a good list of what you really need to do first to improve the performance of the code. However I would just throw out the code and implement the effect on higher level so that Java can utilize native code and GPU.

Radial blur

Based on the screenshot it looks like the effect you are looking for is radial blur with rotation. These can be implemented by first rendering the scene to an offscreen image instead of directly to the screen and then repeatedly rendering the image to the screen with scaling and rotation. These are operations that Java can accelerate on the GPU automatically and you might get even better performance by creating the offscreen image as VolatileImage. Make sure you are using bilinear filtering for better quality: g.setRenderingHints(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);

In pseudo-code the algorithm would look something like:

render scene to offscreen_image
for i in 1 to N
    scale = any function that returns 1 for the first image and approaches zero when i grows.
    rotation = i * constant
    render offscreen_image to screen with scale and rotation
endfor

When rendering the offscreen_image to the screen, you also probably want to fade it to background color a little. In Java you can do this with AlphaComposite. This should be enough to make your effect fast enough. However there is still room for improvement.

Feedback loop

The rendering time of the implementation above is proportional to N. In some cases, mainly if your frame rate is constant, you can further accelerate the rendering by keeping the previous rendering result in the offscreen image and rendering only one copy of the offscreen image. This makes the effect very fast, but the dependency of previous rendering results might be undesirable. This also limits the shape of the scaling and rotation functions. The pseudo-code for that would be:

render scene on top of offscreen_image_1 without clearing
scale = constant_1
rotation = constant_2
render offscreen_image_1 to offscreen_image_2 with scale and rotation
render offscreen_image_2 to screen
swap offscreen_image_1 and offscreen_image_2

Scale and rotation constants can still vary based on time / framecounter in this version.

You might have seen this effect in action in some music player visualization (Winamp, Media Player etc.). Here is an example video: https://www.youtube.com/watch?v=jasdVfbAFVw#t=237s.

share|improve this answer

Per-pixel image processing on the CPU is something where microöptimization is worth thinking about from the start. You're doing memory allocation and object initialization on a per-pixel basis; this is probably most of your problem.

The first thing you should do is figure out how to use only arrays of primitives (byte[] etc.) to perform your computation.

  • Do not use ArrayList, but only arrays.
  • Do not use Integer, but only int, byte, etc.
  • Do not use arrays of arrays, but use a flat array and compute coordinates like arr[x + width * y].
  • Do not allocate any arrays (new byte[]) inside a loop.

Once you have this taken care of (and it'll probably help a lot), the next step is to get rid of your single-pixel image access operations (getRGB and setRGB). Instead, get an entire array of pixels from the image and write back the same way; I'm sure BufferedImage has operations to retrieve and store the image data as arrays, but I'm not familiar enough with it to recommend specific methods.

share|improve this answer
    
Thanks for the suggestions! I've applied a few and it's improved the speed, but still nothing near the ~10 ms I need. Looking at a different algorithm now –  nullptr Apr 13 '13 at 2:18
    
“A few”? I strongly recommend that you at least go far enough to make sure there are no objects being created, no memory allocation, inside your loops. –  Kevin Reid Apr 13 '13 at 2:54

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.