I'm searching for a nice and easy way to generate a mask for an island map with C#.
Basically I'm using with a random heightmap generated with perlin noise, where the terrain is NOT surrounded by water.
The next step would be to generate a mask, to ensure the corners and borders are just water.
Then I can just subtract the mask from the perlin noise image to get an island.
and playing around with the contrast..
and the gradient curve, I can get an island heightmap just like I want it..
(these are just examples of course)
so as you can see, the "edges" of the island are just cut off, which is not a big problem if the colour value is not too white, because I will just divide the grayscale into 4 layers (water, sand, grass and rock).
My question is, how can I generate a good looking mask like in the second image?
UPDATE
I've found this technique, it seems to be a nice starting point for me, but I'm not sure how exectly I can implement it to get the desired output. http://mrl.nyu.edu/~perlin/experiments/puff/
UPDATE 2
this is my final solution.
I've implemented the makeMask()
function inside my normalisation loop like this:
//normalisation
for( int i = 0; i < width; i++ ) {
for( int j = 0; j < height; j++ ) {
perlinNoise[ i ][ j ] /= totalAmplitude;
perlinNoise[ i ][ j ] = makeMask( width, height, i, j, perlinNoise[ i ][ j ] );
}
}
and this is the final function:
public static float makeMask( int width, int height, int posX, int posY, float oldValue ) {
int minVal = ( ( ( height + width ) / 2 ) / 100 * 2 );
int maxVal = ( ( ( height + width ) / 2 ) / 100 * 10 );
if( getDistanceToEdge( posX, posY, width, height ) <= minVal ) {
return 0;
} else if( getDistanceToEdge( posX, posY, width, height ) >= maxVal ) {
return oldValue;
} else {
float factor = getFactor( getDistanceToEdge( posX, posY, width, height ), minVal, maxVal );
return oldValue * factor;
}
}
private static float getFactor( int val, int min, int max ) {
int full = max - min;
int part = val - min;
float factor = (float)part / (float)full;
return factor;
}
public static int getDistanceToEdge( int x, int y, int width, int height ) {
int[] distances = new int[]{ y, x, ( width - x ), ( height - y ) };
int min = distances[ 0 ];
foreach( var val in distances ) {
if( val < min ) {
min = val;
}
}
return min;
}
this will give an output like in the image #3.
with a little bit of change in the code, you can get the originally wanted output like in image #2 ->
public static float makeMask( int width, int height, int posX, int posY, float oldValue ) {
int minVal = ( ( ( height + width ) / 2 ) / 100 * 2 );
int maxVal = ( ( ( height + width ) / 2 ) / 100 * 20 );
if( getDistanceToEdge( posX, posY, width, height ) <= minVal ) {
return 0;
} else if( getDistanceToEdge( posX, posY, width, height ) >= maxVal ) {
return 1;
} else {
float factor = getFactor( getDistanceToEdge( posX, posY, width, height ), minVal, maxVal );
return ( oldValue + oldValue ) * factor;
}
}