Ich suche nach einer schönen und einfachen Möglichkeit, mit C # eine Maske für eine Inselkarte zu generieren.
Grundsätzlich benutze ich eine zufällige Höhenkarte, die mit Perlinrauschen erzeugt wurde, wobei das Gelände NICHT von Wasser umgeben ist.
Der nächste Schritt wäre, eine Maske zu generieren, um sicherzustellen, dass die Ecken und Ränder nur Wasser sind.
Dann kann ich einfach die Maske vom Perlin-Rauschbild subtrahieren, um eine Insel zu erhalten.
und mit dem Kontrast herumspielen ..
und der Gradientenkurve kann ich eine Inselhöhenkarte bekommen, wie ich es will ..
(Dies sind nur Beispiele natürlich)
Wie Sie sehen können, werden die "Ränder" der Insel einfach abgeschnitten, was kein großes Problem ist, wenn der Farbwert nicht zu weiß ist, da ich die Graustufen einfach in 4 Schichten (Wasser, Sand, Gras und Rock).
Meine Frage ist, wie kann ich eine gut aussehende Maske wie im zweiten Bild erzeugen?
AKTUALISIEREN
Ich habe diese Technik gefunden, sie scheint ein guter Ausgangspunkt für mich zu sein, aber ich bin mir nicht sicher, wie genau ich sie implementieren kann, um die gewünschte Ausgabe zu erzielen. http://mrl.nyu.edu/~perlin/experiments/puff/
UPDATE 2
Das ist meine endgültige Lösung.
Ich habe die makeMask()
Funktion in meiner Normalisierungsschleife folgendermaßen implementiert :
//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 ] );
}
}
und das ist die letzte Funktion:
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;
}
Dies ergibt eine Ausgabe wie in Bild 3.
Mit ein wenig Änderung im Code können Sie die ursprünglich gewünschte Ausgabe wie in Bild 2 erhalten ->
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;
}
}