The Perlin noise implementations I have used have all imposed high cpu costs.
You can try variants like these, and profile them:
- write into an array vs writing directly into the BufferedImage via a Raster, then place the array into the image via a single operation
- try using a single values for all the colors & alpha merged into one value vs setting each channel separately.
- make a new image each time vs editing an existing image.
Unfortunately, my memory is hazy as to the how much effect any of this had. My best recollection is that there may not be a whole lot to be gained here relative to the processing time of each Noise lookup.
BurntPizza gave the main strategies. I’d add: use the lowest dimension noise that works. 3D noise is significantly more costly than 2D. And on using fewer noise layers: I wonder if sometimes people get stuck on sticking with “octaves” for multiple layers when a different scaling would suffice. It may be possible to get a good-enough looking graphic by leaving off some of the octaves or using scalings other than powers of 2.
Classic case:
1/2 Noise(x * (baseFactor / 0.5), y * (baseFactor / 0.5)
- 1/4 Noise(x * (baseFactor / 0.25), y * (baseFactor / 0.25)
- 1/8 Noise(x * baseFactor / 0.125), y * (baseFactor / 0.125)
- … for as many channels as visible within the screen resolution.
This gets to be expensive, and maybe better suited for non-realtime situations, where you make a graphic in advance and save the data for later use.
But one could also skip every second line, or progress via a different fraction, e.g., via 1/3rds instead of 1/2.
SiVi is helpful for trying out different formulations. You can bring up the classic cloud from the “Gallery” and then mess with the scaling settings, with quick visual feedback. The example uses 5 channels, but one can get pretty nice clouds with just three. (I’m happy to help with instructions for using this tool, if you have questions. Just IM me.)
http://www.java-gaming.org/user-generated-content/members/27722/sivi.jar
I’m not clear on the second question. Yes, the alpha channel affects all the other channels equally. Do you want the result to have three alpha steps? I tend to make a Map beforehand, and have the noise value serve as a lookup into the Map. That in itself can help reduce the amount of processing, if you are using calculations to get to each R, G, B, and A value.
I’ve also tried things like making a smaller area and reusing the data via reflections or some other transform. There is also the possibility of making a smaller image and scaling it to a larger size in the drawing process via
g.drawImage(x, y, width, height)
I haven’t tried this yet. Just brainstorming. It might look like crap or require specific RenderingHints to make it work. But if you could double the size of the graphic and still use it, that cuts the Perlin processing to 1/4 of what is otherwise needed.