ANDROID Perlin Noise clouds & CPU-Usage & Bitmaps

Hi there,

I know there are probably millions of topics out there about this, but I can’t seem to find a good tutorial on how to do it. The problem is that the FPS drops… Are there any CPU-friendly ways to do it? Or shall I just have a noise tileset. I’ve already implemented a Perlin Noise gen. If there is any article about it, let me know.

As you probably know it needs an alpha level, yet I don’t know how to accomplish it, because the bitmap is like only changing the alpha-level of all the pixels… The clouds only have 1 color and 3 alpha levels(AL). the first AL is like 0% transperant, the second AL is like 33% Transperant etc…

So basically, how to make clouds and changing alpha levels of them. Only use words if you can, I need to write my own program and learn from it ^w^!

-RoseSlayer

Post scriptum: if you have any questions just ask them!

Either 1) do less work or 2) split up the work.

1: Use a faster noise algorithm, and/or use fewer noise layers, etc. Or use a pre-rendered tileset.
2: Multithread cloud generation as noise is a parallel problem.

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.

A small aside - in “industry” it is apparently rather rare to use more than 3 layers of noise; on extra special occasions they’ll go up to 5 apparently. Can’t remember where I read that but I was researching simplex noise the other day and came across it from someone who worked making the special effects for various movies.

Cas :slight_smile:

In regards to memory access, obtaining the array from the BufferedImage (if using J2D ofc) is the fastest method in every case I have come across.
Even better if you can use a single channel type like TYPE_BYTE_GRAY since then each pixel only requires a single byte written, although some types may not blit quickly. Always measure.

Don’t create new images each time, at least if they are of significant size. In my experience that is an issue which greatly benefits from an object pool, as here.

If multithreading, make sure not to interleave write positions but instead divide the image into (hopefully maximal) sections: Thread 1 does indices 0-1023, 2 does 1024-2047, etc. so as to maximize locality and minimize false sharing which can otherwise suck the performance right out without you knowing.

considering the effect that will happen on screen, to do an operation for every single pixel on screen seems really too much. let alone more passes

so I can absolutely understand why the industry wouldnt bother, there is easier ways with premade content, not having the cpu make everything

It turns out that drawing a smaller Perlin animation at a larger size doesn’t look half bad! I’m taking a 64 x 128 image and stretching it to 96 x 288. I had to tinker a bit with the scaling used inside the Simplex call to make the texture a bit busier, not a big deal.

First attempt, drawing a 50 x 100 image at size 100 x 300 was too much. Some of the stepping became visible. Maybe results will vary on different screens?

The resulting image is used 6 times, 3 of them in reverse orientation. It seems like this is a viable way to cover a fair bit of screen with a reasonable cpu cost.

After some testing, i’ve proved that the Perlin Noise doesn’t use alot of CPU, it’s the creating of the bitmaps…
I think I’ve a really inefficient way of generating the Bitmap

public Bitmap generateClouds(int image, int depth, int height, int ex, int ey){
		Bitmap mask = BitmapFactory.decodeResource(getResources(), image, options);
		Bitmap clouds = createBitmap(mask.getWidth(), mask.getHeight());
		
		SimplexNoise sn = new SimplexNoise();
		int pixels[] = new int[mask.getWidth()*mask.getHeight()];
		for(int y = 0; y < mask.getHeight(); y++){
			for(int x = 0; x < mask.getWidth(); x++){
				if(!isTransparant(image, x, y)){
					int z = (int)(depth+(sn.octavedNoise(x + ex, y + ey, 3, 0.4f, 0.05f)+0.5)*(height-depth));
					if(z > 120){ //<Generates big clouds..
						pixels[x+y*mask.getWidth()] = Colors.white;
					} else {
						pixels[x+y*mask.getWidth()] = Colors.transparent;
					}
				}
			}
		}
		
		System.out.println(pixels);
		clouds.setPixels(pixels, 0, mask.getWidth(), 0, 0, mask.getWidth(), mask.getHeight());
		
		return clouds;
	}

Mask:

Result:
Whilst it provides a good result, it has a FPS of 3-6…

At the start of the game, it starts to generates like 16-22 Bitmaps and the time it takes is 20s…

Ah, well if this is on Android, then all bets are off.

Well, it’s a big twist, but whilst this topic was mainly about the generation of clouds using Perlin Noise, the rendering of the clouds are causing a problem…

Did you profile it? What’s in isTransparent(…)?

Then don’t create a new Bitmap every time and recycle Bitmaps. Make two Bitmaps (mask and target) parameters to “generate clouds”. Handle the error case when mask and target are not the same size. Certainly the “clouds” bitmap can be recycled. I don’t know how many mask images you load or how often this method is called.

	public boolean isTransparant(int image, int x, int y){
		if(getColor(image, x, y) == Colors.transparent){
			return true;
		}
		return false;
	}

I don’t know if it is better to retrieve the pixels[] of the mask and only change the integers in that, that doesn’t have the value 0 (which is transparent)… Changing that right now, and checking if it is a better way.

Recycling it is indeed a better way, but I don’t know if that is really efficient, because if you want to overwrite a bitmap you need to make a copy (or I am wrong, kinda new to Android) But I am giving it a try

[Edit]:
O wow, it takes like some milliseconds to generate the entire map instead of 20 seconds… Reusing the Bitmaps with

options.inMutable = true;

is like the heaven of speed ^w^!

And for the isTransparent fuction, i changed it to just retrieve the pixels[] from the mask and don’t do anything if the value is 0 which is transparent. Because the getPixel function is probably not the most efficient function out there…
Thanks for all the help but I am still stuck with the Perlin Noise question, how can you really have cloudy effects (I am just shifting the x and y value). Like the effects that make the perlin noise clouds look like they are ‘blooming’…

-RoseSlayer

Use the z-axis (use 3D noise).

That would (probably) look strange and be significantly slower…
What I was thinking is you could map the 2D noise over the sphere, probably using a “fisheye lens” type of mapping so that the clouds would actually look like they are wrapping around a sphere.
Something like what this probably looks like: http://stackoverflow.com/questions/6214377/fisheye-distortion?rq=1

EDIT: for the actual function, see the “Orthographic” section under http://en.wikipedia.org/wiki/Fisheye_lens#Fisheye_lens

The fisheye thing could be pretty cool, but the 3D approach also works for a blooming effect. Yes, it is slower than 2D. Have to keep the size down and limit to 3 octaves.

http://hexara.com/Images/perlinClouds.gif

(Made with SiVi, adding only z-axis animation to a cloud texture.)

Ah, I believe I mixed up what the desired effect was… (I still suggest the lens)

Both combined would definitely look good. If the 3D is too slow (probably won’t be if you don’t compute too many layers of z), then you could fake it by thresholding the 2D noise.

you may try this way :

Implement the following in a C Library using Android NDK
http://www.java-gaming.org/index.php?topic=23771.0

then in your Java you will use it like this :

 
static 
{
  System.loadLibrary("yourlibrary");
}
private static native void render(Bitmap  bitmap,byte[] imageBuffer,int width,int height);
private Bitmap bitmap=Bitmap.createBitmap(width,height,Bitmap.Config.ARGB_8888);
...
...
public void renderImage()
{
 render(bitmap,data,width,height);
}

EDIT: I managed to perform real time camera image manipulation using ndk on galaxy S so it should be fast enought, also multithreading idea mentionned above is good

Below the C source code for generating a gray image with 50% alpha.

It must be adapted for your project package and class name, here the package is “net.dzzd.camera” and the class name “OverlayView” => Java_net_dzzd_camera_OverlayView_render


#include <jni.h>
#include <time.h>
#include <android/log.h>
#include <android/bitmap.h>

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define  LOG_TAG    "native"
#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define  LOGW(...)  __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)

/* Set to 1 to enable debug log traces. */
#define DEBUG 0	


JNIEXPORT void JNICALL Java_net_dzzd_camera_OverlayView_render(JNIEnv * env, jobject  obj, jobject bitmap, jbyteArray data,jint width,jint height)
{

    AndroidBitmapInfo  info;
    void*	           pixels;
	jboolean 		   isVideoDataCopy;
	
    AndroidBitmap_getInfo(env, bitmap, &info);
    AndroidBitmap_lockPixels(env, bitmap, &pixels);
	
	int outputOfxXY;

	for(int y=1;y<info.height-1;y++)
		for(int x=1;x<info.width-1;x++)
		{
			outputOfxXY=x+y*info.width;
			
			int A=128;
			int R=128;
			int G=128;
			int B=128;
			
			int ARGB=R | (G<<8) | (B<<16) | (A<<24);
			((uint32_t*)pixels)[outputOfxXY] = ARGB;
		}

    AndroidBitmap_unlockPixels(env, bitmap);
    
}