Estou procurando uma maneira fácil e agradável de gerar uma máscara para um mapa de ilha com C #.
Basicamente, estou usando um mapa de altura aleatório gerado com ruído permanente, onde o terreno NÃO é cercado por água.
O próximo passo seria gerar uma máscara, para garantir que os cantos e bordas sejam apenas água.
Depois, posso subtrair a máscara da imagem de ruído permanente para obter uma ilha.
e brincando com o contraste ..
e a curva de gradiente, posso obter um mapa de altura da ilha exatamente como eu quero.
(estes são apenas exemplos, é claro)
como você pode ver, as "bordas" da ilha são cortadas, o que não é um grande problema se o valor da cor não for muito branco, porque vou dividir a escala de cinza em 4 camadas (água, areia, grama e Rocha).
Minha pergunta é: como posso gerar uma máscara bonita como na segunda imagem?
ATUALIZAR
Eu encontrei essa técnica, parece ser um bom ponto de partida para mim, mas não tenho certeza de como exatamente posso implementá-la para obter a saída desejada. http://mrl.nyu.edu/~perlin/experiments/puff/
ATUALIZAÇÃO 2
Esta é a minha solução final.
Eu implementei a makeMask()
função dentro do meu loop de normalização assim:
//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 ] );
}
}
e esta é a função final:
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;
}
isso dará uma saída como na imagem # 3.
com um pouco de alteração no código, você pode obter a saída originalmente desejada, como na imagem # 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;
}
}