Я ищу хороший и простой способ создать маску для карты острова с помощью C #.
В основном я использую случайную карту высот, сгенерированную с помощью перлин-шума, где ландшафт НЕ окружен водой.
Следующим шагом будет создание маски, чтобы углы и границы были просто водой.
Тогда я могу просто вычесть маску из изображения перлин-шума, чтобы получить остров.
и играть с контрастом ..
и кривая градиента, я могу получить карту высот острова так, как я этого хочу ..
(это всего лишь примеры, конечно)
так что, как вы можете видеть, «края» острова просто обрезаются, что не является большой проблемой, если значение цвета не слишком белое, потому что я просто разделю оттенки серого на 4 слоя (вода, песок, трава и камень).
Мой вопрос, как я могу создать красивую маску, как на втором изображении?
ОБНОВИТЬ
Я нашел эту технику, она мне кажется хорошей отправной точкой, но я не уверен, насколько точно я могу ее реализовать, чтобы получить желаемый результат. http://mrl.nyu.edu/~perlin/experiments/puff/
ОБНОВЛЕНИЕ 2
это мое окончательное решение.
Я реализовал makeMask()
функцию внутри цикла нормализации следующим образом:
//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 ] );
}
}
и это последняя функция:
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;
}
это даст вывод, как на картинке # 3.
с небольшими изменениями в коде вы можете получить исходный искомый вывод, как на изображении №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;
}
}