2016-01-04 1 views
1

Je fabrique donc un générateur de cartes qui crée des îlots aléatoires. Il utilise Perlin Noise au cœur du générateur puis une méthode utilisant des cercles avec des gradients pour faire les îles. La méthode circle crée un certain nombre de cercles dans le centre de la carte avec un dégradé d'une couleur commençant à 64 jusqu'à 0. Le problème est que cette méthode crée un aspect non-natif des parties de la carte avec bords circulaires. Lorsque le bruit perlin est généré pour un pixel, il obtient ce pixel sur la carte de dégradé, puis le multiplie par la valeur bleue. Donc, si le bruit perlin donne un sur pixel 1, 5 et la valeur bleue sur la carte de gradient est 54, il produira une valeur de bruit de 54. Si le bruit perlin sur le pixel 130, 560 est de 0,5 et le gradient valeur de couleur est 64 la valeur de bruit de 32Cercles de gradients pour le générateur de cartes

Voici ce que je reçois:

Picture of what I am getting

Il y a deux points clés du code, le bit Perlin:

noise = NoiseGenerator.Noise(x, y); 
double gradColour = getGradColour(x, y).B; 
double addedNoise = noise * gradColour; 
double gradNoise = addedNoise;// - gradColour; 

Et puis le générateur de carte de gradient:

public static void DrawGrad(float X, float Y, float R, Color C1, Color C2) 
    { 
     Graphics g = Graphics.FromImage(imgGrad); 
     GraphicsPath path = new GraphicsPath(); 
     path.AddEllipse(X, Y, R, R); 

     PathGradientBrush pathGrBrush = new PathGradientBrush(path); 
     pathGrBrush.CenterColor = C1; 

     Color[] colours = { C2 }; 
     pathGrBrush.SurroundColors = colours; 
     g.FillEllipse(pathGrBrush, X, Y, R, R); 
     //g.FillEllipse(Brushes.Red, X, Y, R, R); 
     g.Flush(); 
    } 

     int amount = rnd.Next(25, 30); 
     for (int i = 0; i < amount/4; i++) 
     { 
      float X = rnd.Next(-800, 1748); 
      float Y = rnd.Next(-800, 1748); 
      float R = rnd.Next(1000, 1200); 
      DrawGrad(X, Y, R, Color.FromArgb(255, 0, 0, rnd.Next(15, 20)), Color.FromArgb(0, 0, 0, 0)); 
     } 
     for (int i = 0; i < amount; i++) 
     { 
      double positionDiv = 1.98; 
      double X1 = rnd.Next(0, 450)/positionDiv; 
      double Y1 = rnd.Next(0, 450)/positionDiv; 
      double R1 = rnd.Next(300, 650)/4; 
      float R = (float)R1; 
      float X = (float)X1; 
      float Y = (float)Y1; 

      while (X + R > 1004) 
      { 
       X = 924 - R; 
      } 
      while (Y + R > 1004) 
      { 
       Y = 924 - R; 
      } 
      if(X < 30) 
      { 
       X = 30; 
      } 
      if(Y < 30) 
      { 
       Y = 30; 
      } 
      DrawGrad(X, Y, R, Color.FromArgb(255, 0, 0, rnd.Next(40, 64)), Color.FromArgb(0, 0, 0, rnd.Next(13, 17))); 
     } 

Je me demandais si quelqu'un d'autre connaît d'autres méthodes en C# qui pourrait créer une île en utilisant un bruit de Perlin? Tout avis serait grandement apprécié.

+1

Veuillez inclure du code pour montrer ce que vous avez essayé. –

+0

Voir aussi des images de ce que vous avez et ce que vous voulez créer aiderait .. – TaW

+0

Ajouté comme demandé. – Richard

Répondre

2

Comme je l'ai mentionné dans le commentaire diamant et carré est beaucoup plus facile avec des résultats assez bons. Ainsi, l'algorithme:

  1. propriétés de génération de configuration

    Ici, vous devez avoir un ensemble de paramètres comme min, élévation max, niveau de la mer, l'altitude varie pour la végétation, le sable/rock/saleté, etc, paramètres de pente, etc.

  2. créer carte de la hauteur du terrain je l'appelle zed[][]

    Pour cela, vous nE ne ed légèrement modifié algorithme Diamond&Square. Le problème est que cet algorithme produit un terrain "intérieur".

    Pour l'ajuster afin qu'il produise des terrains de type îlot, vous devez l'initialiser avec la plus faible élévation possible dans les coins. De plus, vous devez ignorer le premier pas de diamant et initialiser le point milieu avec une valeur aléatoire à la place (pas la moyenne des coins). Et après chaque itération, corrigez les points de la bordure à l'élévation minimale (sous l'eau) (ou une valeur aléatoire près de celle-ci).

    Pour obtenir la bonne sortie, j'utilise approximativement la plage <-2^15 , 2^16> pendant la génération. Après cela, je trouve l'élévation min et max dans le terrain généré et redimensionne les gammes d'élévation configurées.

    Ne pas oublier que le diamant et le carré ont besoin d'une carte de résolution (2^n)+1 !!!

  3. créer carte de surface Je l'appelle typ[][]

    Lorsque la carte du terrain est terminé, vous pouvez ajouter des fonctions à base d'altitude comme celles-ci dans l'ordre croissant:

    • Watter, le sable, le type de végétation, roches Mountine , la neige

    ajouter ensuite les paramètres en fonction de la pente du terrain

    • roches

    Ensuite, vous pouvez ajouter des choses supplémentaires comme (basé sur des règles):

    • rivières, cours d'eau, Watter-chutes, la construction, les routes, ...

je le fais en C++ comme ceci:

void map_random(int _xs,int _ys) 
    { 
    // config 
    int h0=-1000,h1=3000;  // [m] terrain elevation range 
    int h_water= 0;    // [m] sea level 
    int h_sand=15;    // [m] sand level 
    int h_evergreen=1500;  // [m] evergreen level 
    int h_snow=2000;   // [m] snow level 
    int h_rock=1800;   // [m] mountine rock level 
    float a_rock=60.0;   // [deg] mountine rock slope 
    float d_pixel=15.0;   // [m] pixel size 
    bool _island=true; 

    // types 
    enum _cover_enum 
     { 
     _cover_none=0, 
     _cover_water, 
     _cover_snow, 
     _covers, 
     _cover_shift=0, 
     _cover_mask=15, 
     }; 
    DWORD _cover[_covers]= 
     { 
     // RRGGBB 
     0x00000000,  // none 
     0x00004080,  // water 
     0x008F8F8F,  // snow 
     }; 
    enum _terrain_enum 
     { 
     _terrain_enum_beg=-1, 
     _terrain_dirt, 
     _terrain_sand, 
     _terrain_rock, 
     _terrains, 
     _terrain_shift=4, 
     _terrain_mask=15, 
     }; 
    DWORD _terrain[_terrains]= 
     { 
     // RRGGBB 
     0x00301510,  // dirt 
     0x00EEC49A,  // sand 
     0x00777777,  // rock 
     }; 
    enum _flora_enum 
     { 
     _flora_enum_beg=-1, 
     _flora_none, 
     _flora_grass, 
     _flora_hardwood, 
     _flora_evergreen, 
     _flora_deadwood, 
     _floras, 
     _flora_shift=8, 
     _flora_mask=15, 
     }; 
    DWORD _flora[_floras]= 
     { 
     // RRGGBB 
     0x00000000,  // none 
     0x007F7F3F,  // grass 
     0x001FFF1F,  // hardwood 
     0x00007F00,  // evergreen 
     0x007F3F1F,  // deadwood 
     }; 

    // variables 
    float a,b; int c,t,f; 
    int x,y,z,xx,yy,mxs,mys,dx,dy,dx2,dy2,r,r2; 
    int **ter=NULL,**typ=NULL; 
    Randomize(); 
    // align resolution to power of 2 
    for (mxs=1;mxs+1<_xs;mxs<<=1); if (mxs<3) mxs=3; 
    for (mys=1;mys+1<_ys;mys<<=1); if (mys<3) mys=3; 
    ter=new int*[mys+1]; for (y=0;y<=mys;y++) ter[y]=new int[mxs+1]; 
    typ=new int*[mys+1]; for (y=0;y<=mys;y++) typ[y]=new int[mxs+1]; 

    // [Terrain] 

    // diamond & square random height map -> ter[][] 
    dx=mxs; dx2=dx>>1; r=1<<16;      // init step,half step and randomness 
    dy=mys; dy2=dy>>1; r2=r>>1; 
    // set corners values 
    if (_island) 
     { 
     t=-r2; 
     ter[ 0][ 0]=t; 
     ter[ 0][mxs]=t; 
     ter[mys][ 0]=t; 
     ter[mys][mxs]=t; 
     ter[dy2][dx2]=r2; 
     } 
    else{ 
     ter[ 0][ 0]=Random(r); 
     ter[ 0][mxs]=Random(r); 
     ter[mys][ 0]=Random(r); 
     ter[mys][mxs]=Random(r); 
     } 
    for (;dx2|dy2;dx=dx2,dx2>>=1,dy=dy2,dy2>>=1) // subdivide step until full image is filled 
     { 
     if (!dx) dx=1; 
     if (!dy) dy=1; 
     // diamond (skip first one for islands) 
     if ((!_island)||(dx!=mxs)) 
     for (y=dy2,yy=mys-dy2;y<=yy;y+=dy) 
      for (x=dx2,xx=mxs-dx2;x<=xx;x+=dx) 
      ter[y][x]=((ter[y-dy2][x-dx2]+ter[y-dy2][x+dx2]+ter[y+dy2][x-dx2]+ter[y+dy2][x+dx2])>>2)+Random(r)-r2; 
     // square 
     for (y=dy2,yy=mys-dy2;y<=yy;y+=dy) 
     for (x=dx ,xx=mxs-dx ;x<=xx;x+=dx) 
      ter[y][x]=((ter[y][x-dx2]+ter[y][x+dx2]+ter[y-dy2][x]+ter[y+dy2][x])>>2)+Random(r)-r2; 
     for (y=dy ,yy=mys-dy ;y<=yy;y+=dy) 
     for (x=dx2,xx=mxs-dx2;x<=xx;x+=dx) 
      ter[y][x]=((ter[y][x-dx2]+ter[y][x+dx2]+ter[y-dy2][x]+ter[y+dy2][x])>>2)+Random(r)-r2; 
     for (x=dx2,xx=mxs-dx2;x<=xx;x+=dx) 
      { 
      y= 0; ter[y][x]=((ter[y][x-dx2]+ter[y][x+dx2]+ter[y+dy2][x])/3)+Random(r)-r2; 
      y=mys; ter[y][x]=((ter[y][x-dx2]+ter[y][x+dx2]+ter[y-dy2][x])/3)+Random(r)-r2; 
      } 
     for (y=dy2,yy=mys-dy2;y<=yy;y+=dy) 
      { 
      x= 0; ter[y][x]=((ter[y][x+dx2]+ter[y-dy2][x]+ter[y+dy2][x])/3)+Random(r)-r2; 
      x=mxs; ter[y][x]=((ter[y][x-dx2]+ter[y-dy2][x]+ter[y+dy2][x])/3)+Random(r)-r2; 
      } 

     // adjust border 
     if (_island) 
      { 
      for (y=0;y<=mys;y+=dy2) { ter[y][0]=t; ter[y][mxs]=t; } 
      for (x=0;x<=mxs;x+=dx2) { ter[0][x]=t; ter[mys][x]=t; } 
      } 

     // adjust randomness 
     // r=(r*100)>>8; if (r<2) r=2; r2=r>>1; 
     r>>=1; if (r<2) r=2; r2=r>>1; 
     } 
    // rescale to <h0,h1> 
    xx=ter[0][0]; yy=xx; 
    for (y=0;y<mys;y++) 
    for (x=0;x<mxs;x++) 
     { 
     z=ter[y][x]; 
     if (xx>z) xx=z; 
     if (yy<z) yy=z; 
     } 
    for (y=0;y<mys;y++) 
    for (x=0;x<mxs;x++) 
     ter[y][x]=h0+(((ter[y][x]-xx)*(h1-h0))/(yy-xx)); 

    // [Surface] 

    for (y=0;y<mys;y++) 
    for (x=0;x<mxs;x++) 
     { 
     z=ter[y][x]; 
     // max slope [deg] 
     a=atan2(ter[y][x+1]-z,d_pixel); 
     b=atan2(ter[y+1][x]-z,d_pixel); 
     if (a<b) a=b; a*=180.0/M_PI; 

     c=_cover_none; 
     if (z<=h_water) c=_cover_water; 
     if (z>=h_snow) c=_cover_snow; 

     t=_terrain_dirt; 
     if (z<=h_sand) t=_terrain_sand; 
     if (z>=h_rock) t=_terrain_rock; 
     if (a>=a_rock) t=_terrain_rock; 

     f=_flora_none; 
     if (t==_terrain_dirt) 
      { 
      r=Random(100); 
      if (r>10) f=_flora_grass; 
      if (r>50) 
       { 
       if (z>h_evergreen) f=_flora_evergreen; 
       else{ 
        r=Random(h_evergreen); 
        if (r<=z) f=_flora_evergreen; 
        else  f=_flora_hardwood; 
        } 
       } 
      if (r<5) f=_flora_deadwood; 
      } 
     typ[y][x]=(c<<_cover_shift)|(t<<_terrain_shift)|(f<<_flora_shift); 
     } 

    // [copy data] rewrite this part to suite your needs it just compute color based on type of terrain and height 
    // ter[][] is elevation in meters 
    // typ[][] is surface type 
/* 
    for (y=0;y<_ys;y++) 
    for (x=0;x<_xs;x++) 
     pic.p[y][x].dd=(((ter[y][x]-h0)*255)/(h1-h0))*0x00010101; 
    for (y=0;y<_ys;y++) 
    for (x=0;x<_xs;x++) 
     { 
     r=typ[y][x]; 
     c=(r>> _cover_shift)& _cover_mask; 
     t=(r>>_terrain_shift)&_terrain_mask; 
     f=(r>> _flora_shift)& _flora_mask; 
       r=_terrain[t]; 
     if (c) r= _cover[c]; 
     if (c==_cover_water) 
      { 
      xx=256-((ter[y][x]<<7)/h0); 
      yy=int(r>>16)&255; yy=(yy*xx)>>8; r=(r&0x0000FFFF)|(yy<<16); 
      yy=int(r>> 8)&255; yy=(yy*xx)>>8; r=(r&0x00FF00FF)|(yy<< 8); 
      yy=int(r )&255; yy=(yy*xx)>>8; r=(r&0x00FFFF00)|(yy ); 
      } 
     if (f){ if (c) r|=_flora[f]; else r=_flora[f]; }; 
     pic.p[y][x+_xs].dd=r; 
     } 
*/  
    // free ter[][],typ[][] 
    for (y=0;y<=mys;y++) delete[] ter[y]; delete[] ter; ter=NULL; 
    for (y=0;y<=mys;y++) delete[] typ[y]; delete[] typ; typ=NULL; 
    } 

La sortie avec les paramètres actuels est comme ceci:

example

[Notes]

Cette approche produisent généralement seule grande colline sur l'île. (Inland est générée OK) Si vous en voulez plus, vous pouvez créer plus de cartes de terrain et les calculer ensemble.

Je fais la suite à la place: je place le point central à la hauteur maximale et ignore la première passe de diamant. Après le premier passage carré, j'ai remis le point central à une valeur aléatoire. Cela ajoute la possibilité de plus de collines centrales puis une seule. En utilisant cette approche et l'ajout d'éclairage (ambiante + ombrage normal) pour afficher un aperçu et une légère peaufinage de la taille des pixels (35m) Je suis arrivé à ce résultat:

example

de rares occasions, cela peut générer l'intérieur des terres comme la carte (si la centrale La zone est trop petite Pour la manipuler, vous pouvez balayer les coins pour déterminer s'il y a de la terre à générer à nouveau ou ajouter un peu de biais pour les points centraux.

Vous pouvez jouer avec le code par exemple ajouter des rivières:

  1. trouver topest colline
  2. obtenir l'emplacement aléatoire à proximité/autour
  3. mis à la rivière de type
  4. trouver le plus petit pixel voisin de la hauteur non défini sur le type de rivière
  5. s'il est sur le bord de la carte ou défini sur l'arrêt de type mer/eau autrement boucle n ° 3

    Si vous voulez plus d'une rivière alors n'oubliez pas d'utiliser un type de temp pour les rivières déjà faites afin que l'algorithme fonctionne correctement. Vous pouvez également augmenter le volume de la rivière avec la distance du début ... Voici le résultat:

    rivers

    Après cela, vous devez également égaliser le niveau d'eau des lacs formés.