Sto cercando un modo semplice e piacevole per generare una maschera per una mappa dell'isola con C #.
Fondamentalmente sto usando una mappa di altezza casuale generata con rumore perlin, in cui il terreno NON è circondato dall'acqua.
Il prossimo passo sarebbe quello di generare una maschera, per garantire che angoli e bordi siano solo acqua.
Quindi posso solo sottrarre la maschera dall'immagine del rumore del perlin per ottenere un'isola.
e giocando con il contrasto ..
e la curva del gradiente, posso ottenere una mappa altimetrica dell'isola proprio come la voglio ...
(questi sono solo esempi ovviamente)
come puoi vedere, i "bordi" dell'isola sono semplicemente tagliati, il che non è un grosso problema se il valore del colore non è troppo bianco, perché dividerò la scala di grigi in 4 strati (acqua, sabbia, erba e roccia).
La mia domanda è: come posso generare una maschera di bell'aspetto come nella seconda immagine?
AGGIORNARE
Ho trovato questa tecnica, sembra essere un buon punto di partenza per me, ma non sono sicuro di quanto esattamente posso implementarla per ottenere l'output desiderato. http://mrl.nyu.edu/~perlin/experiments/puff/
AGGIORNAMENTO 2
questa è la mia soluzione finale.
Ho implementato la makeMask()
funzione all'interno del mio ciclo di normalizzazione in questo modo:
//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 questa è la funzione finale:
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;
}
questo darà un output come nell'immagine n. 3.
con un po 'di cambiamento nel codice, puoi ottenere l'output originariamente desiderato come nell'immagine # 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;
}
}