私は、C#を使用して島のマップのマスクを生成するための素敵で簡単な方法を探しています。
基本的には、地形が水に囲まれていないパーリンノイズで生成されたランダムハイトマップを使用しています。
次のステップは、マスクを生成して、角と境界がただの水であることを確認することです。
その後、perlinノイズ画像からマスクを差し引くだけで島を取得できます。
コントラストをいじって
勾配曲線を使用すると、希望どおりに島の高さマップを取得できます。
(これらはもちろん単なる例です)
ご覧のとおり、島の「エッジ」は切り取られていますが、カラー値が白すぎない場合は大きな問題ではありません。グレースケールを4つのレイヤー(水、砂、草、岩)。
私の質問は、2番目の画像のように見栄えの良いマスクをどのように生成できますか?
更新
私はこの手法を見つけましたが、それは私にとって良い出発点のようですが、目的の出力を得るためにどの程度正確に実装できるかわかりません。 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;
}
}