Szukam przyjemnego i łatwego sposobu na wygenerowanie maski mapy wyspy za pomocą C #.
Zasadniczo używam z losową mapą wysokości generowaną z hałasem perlin, gdzie teren NIE jest otoczony wodą.
Następnym krokiem byłoby wygenerowanie maski, aby rogi i granice były tylko wodą.
Następnie mogę odjąć maskę od obrazu szumu perlin, aby uzyskać wyspę.
i bawić się z kontrastem ...
i krzywą gradientu, mogę uzyskać mapę wysokości wyspy tak, jak chcę.
(są to tylko przykłady)
więc, jak widać, „krawędzie” wyspy są po prostu odcięte, co nie jest dużym problemem, jeśli wartość koloru nie jest zbyt biała, ponieważ po prostu podzielę skalę szarości na 4 warstwy (woda, piasek, trawa i skała).
Moje pytanie brzmi: jak mogę wygenerować dobrze wyglądającą maskę, jak na drugim zdjęciu?
AKTUALIZACJA
Znalazłem tę technikę, wydaje mi się, że jest to dobry punkt wyjścia dla mnie, ale nie jestem pewien, jak dokładnie mogę ją wdrożyć, aby uzyskać pożądany efekt. http://mrl.nyu.edu/~perlin/experiments/puff/
AKTUALIZACJA 2
to jest moje ostateczne rozwiązanie.
Zaimplementowałem makeMask()
funkcję w mojej pętli normalizacyjnej w następujący sposób:
//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 ] );
}
}
i to jest ostatnia funkcja:
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;
}
da to wynik jak na obrazku nr 3.
z niewielką zmianą w kodzie, możesz uzyskać pierwotnie poszukiwany wynik, jak na obrazku # 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;
}
}