Comme je l'ai mentionné dans le commentaire diamant et carré est beaucoup plus facile avec des résultats assez bons. Ainsi, l'algorithme:
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.
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
!!!
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
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:
[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:
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:
- trouver topest colline
- obtenir l'emplacement aléatoire à proximité/autour
- mis à la rivière de type
- trouver le plus petit pixel voisin de la hauteur non défini sur le type de rivière
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:
Après cela, vous devez également égaliser le niveau d'eau des lacs formés.
Veuillez inclure du code pour montrer ce que vous avez essayé. –
Voir aussi des images de ce que vous avez et ce que vous voulez créer aiderait .. – TaW
Ajouté comme demandé. – Richard