Je cherche un moyen agréable et facile de générer un masque pour une carte d'île avec C #.
Fondamentalement, j'utilise avec une carte d'altitude aléatoire générée avec du bruit perlin, où le terrain n'est PAS entouré d'eau.
La prochaine étape serait de générer un masque, pour s'assurer que les coins et les bordures ne sont que de l'eau.
Ensuite, je peux simplement soustraire le masque de l'image de bruit perlin pour obtenir une île.
et jouer avec le contraste ..
et la courbe de gradient, je peux obtenir une carte de hauteur d'île comme je le veux ..
(ce ne sont bien sûr que des exemples)
comme vous pouvez le voir, les "bords" de l'île sont juste coupés, ce qui n'est pas un gros problème si la valeur de la couleur n'est pas trop blanche, car je vais juste diviser l'échelle de gris en 4 couches (eau, sable, herbe et Roche).
Ma question est, comment puis-je générer un beau masque comme dans la deuxième image?
MISE À JOUR
J'ai trouvé cette technique, elle semble être un bon point de départ pour moi, mais je ne sais pas exactement comment je peux l'implémenter pour obtenir la sortie souhaitée. http://mrl.nyu.edu/~perlin/experiments/puff/
MISE À JOUR 2
c'est ma dernière solution.
J'ai implémenté la makeMask()
fonction dans ma boucle de normalisation comme ceci:
//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 ] );
}
}
et c'est la fonction 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;
}
cela donnera une sortie comme dans l'image # 3.
avec un peu de changement dans le code, vous pouvez obtenir la sortie initialement souhaitée comme dans l'image # 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;
}
}
Réponses:
Génère un bruit régulier avec un biais pour des valeurs plus élevées vers le centre. Si vous voulez des formes d'îles carrées comme vous le montrez dans votre exemple, j'utiliserais la distance jusqu'au bord le plus proche comme facteur.
Avec ce facteur, vous pouvez utiliser quelque chose comme ce qui suit lors de la génération du bruit de masque:
Où
distanceToNearestEdge
renvoie la distance au bord le plus proche de la carte à partir de cette position. EtisSolid
décide si une valeur entre 0 et 1 est solide (quel que soit votre seuil). C'est une fonction très simple, elle pourrait ressembler à ceci:isSolid (valeur flottante) valeur de retour <solidCutOffValue
Quelle
solidCutOffValue
est la valeur que vous utilisez pour choisir entre solide ou non. Il peut s'agir.5
de fentes égales,.75
de plus solides ou.25
de moins solides.Enfin, ce petit bout
(1 - (d/maxDVal)) * noiseAt(x,y)
. Tout d'abord, nous obtenons un facteur entre 0 et 1 avec ceci:(1 - (d/maxDVal))
Où
0
est sur le bord extérieur et1
sur le bord intérieur. Cela signifie que notre bruit est plus susceptible d'être solide à l'intérieur et non solide à l'extérieur. C'est le facteur que nous appliquons au bruit que nous obtenonsnoiseAt(x,y)
.Voici une représentation plus visuelle de ce que sont les valeurs, car les noms peuvent être trompeurs par rapport aux valeurs réelles:
la source
isSolid
Si vous êtes prêt à épargner un peu de puissance de calcul pour cela, alors vous pouvez utiliser une technique similaire à ce que l'auteur de ce blog a fait. ( NB: si vous souhaitez copier directement son code, c'est en ActionScript). Fondamentalement, il génère des points quasi-aléatoires (c'est-à-dire semble relativement uniforme) et les utilise ensuite pour créer des polygones de Voronoi .
Il définit ensuite les polygones extérieurs sur l'eau et parcourt le reste des polygones, les faisant arroser si un certain pourcentage des polygones adjacents sont de l'eau . Vous vous retrouvez alors avec un masque polygonal représentant grossièrement une île.
À partir de cela, vous pouvez appliquer du bruit aux bords, ce qui donne quelque chose qui ressemble à cela (les couleurs proviennent d'une autre étape non liée):
Vous vous retrouvez alors avec un masque en forme d'île (assez) réaliste, qui répondrait à vos besoins. Vous pouvez choisir de l'utiliser comme masque pour votre bruit Perlin, ou vous pouvez alors générer des valeurs de hauteur basées sur la distance à la mer et ajouter du bruit (bien que cela semble inutile).
la source
Une méthode très simple consiste à créer un gradient radial ou sphérique inverse avec un centre à la largeur / 2 et la hauteur / 2. Pour le masquage, vous voulez soustraire le dégradé du bruit plutôt que de le multiplier. Cela vous donne des rives plus réalistes avec l'inconvénient que les îles ne sont pas nécessairement connectées.
Vous pouvez voir la différence entre la soustraction et la multiplication du bruit avec le gradient ici: http://www.vfxpedia.com/index.php?title=Tips_and_Techniques/Natural_Phenomena/Smoke
Si vous ne savez pas comment créer un dégradé radial, vous pouvez l'utiliser comme point de départ:
N'oubliez pas de mettre à l'échelle votre gradient à la même hauteur que votre carte de hauteur et vous devez toujours prendre en compte votre ligne de flottaison d'une manière ou d'une autre.
Le problème avec cette méthode est que votre champ de hauteur sera centré autour du centre de la carte. Cette méthode, cependant, devrait vous aider à ajouter des entités et à rendre votre paysage plus diversifié, car vous pouvez utiliser l' ajout pour ajouter des entités à votre carte de hauteur.
la source
J'appuie la suggestion d'ollipekka: ce que vous voulez faire, c'est soustraire une fonction de polarisation appropriée de votre carte de hauteur, de sorte que les bords soient garantis sous l'eau.
Il existe de nombreuses fonctions de polarisation appropriées, mais une fonction assez simple est la suivante:
où x et y sont les valeurs de coordonnées, mises à l'échelle pour se situer entre 0 et 1. Cette fonction prend la valeur 0 au centre de la carte (à x = y = 0,5) et tend vers l'infini sur les bords. Ainsi, sa soustraction (mise à l'échelle par un facteur constant approprié) de votre carte de hauteur garantit que les valeurs de hauteur auront également tendance à moins l'infini près des bords de la carte. Choisissez simplement la hauteur arbitraire que vous voulez et appelez-la le niveau de la mer.
Comme le note ollipekka, cette approche ne garantira pas que l'île sera contiguë. Cependant, la mise à l'échelle de la fonction de biais par un facteur d'échelle assez petit devrait la rendre principalement plate dans la zone centrale de la carte (n'affectant donc pas beaucoup votre terrain), avec un biais significatif n'apparaissant que près des bords. Ainsi, cela devrait vous donner une île carrée, principalement contiguë avec, au maximum, quelques minuscules sous-îles près des bords.
Bien sûr, si la possibilité d'un terrain déconnecté ne vous dérange pas, un facteur d'échelle un peu plus grand devrait vous donner plus d'eau et une forme d'île plus naturelle. Le réglage du niveau de la mer et / ou de l'échelle de votre carte de hauteur d'origine peut également être utilisé pour faire varier la taille et la forme des îles résultantes.
la source