如何在方形网格上创建分支静脉/河流状结构 [英] how to create a branching vein/river like structure on a square grid

查看:16
本文介绍了如何在方形网格上创建分支静脉/河流状结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试按程序生成一些河流.

我有一个平面(没有立面概念)方形网格作为基础,想在上面绘制一个分支结构,如图所示.

你能分享一下人们可以用来完成这项工作的步骤吗?

我不是在寻找最快的实现,因为没有实时生成,但更简单的实现将是首选.Lua 是我的语言,但什么都行.

还有一些事情:

  1. 形状应通过算法生成.
  2. 形状应该是可使用种子值进行控制.

解决方案

我认为生成河流是一种落后的方法,因为您以后需要根据它们的形状来调整很多东西,这会很困难.相反,我会创建随机地形高度图并从中提取特征(如在现实世界中),这更容易且更接近现实.在最终地图中,您忽略高度并使用平面地图(如果您真的想要平面地图).以下是您可以从高度图中提取的一些内容:

  1. 河流和湖泊

    通过随机播种高海拔点并跟随它下坡到海平面或地图边缘.

  2. 植被或地面

    根据坡度和高度,您可以确定地面是沙子、泥土还是岩石.如果有树木、灌木、草地或其他任何东西.

看看这个QA:

您调整地形生成的方式也会影响河流的形状(无需只生成岛屿).

Seeds 也在为这种方法工作.

[Edit1] 承诺的 C++ 代码

这基本上生成随机高度图,然后种子和下坡跟随河流(如果地形阻止下坡水流,则会自动生成湖泊).地形类型也由坡度和高度决定.

//---------------------------------------------------------------------图片图片;//---------------------------------------------------------------------------void map_random(int _xs,int _ys){//配置int h0=-1000,h1=3000;//[m] 地形高程范围int h_water = 0;//[m] 海平面int h_sand=15;//[m] 沙位int h_evergreen=1500;//[m] 常绿级别int h_snow=2000;//[m] 雪层int h_rock=1800;//[m] 山岩水平浮动 a_rock=60.0;//[deg] 山岩斜坡浮动 d_pixel=35.0;//[m] 像素大小int d_river_w=5;//[像素] 河流最大宽度int d_river_l=150;//[像素]河底长度每宽度增加布尔_岛=真;//类型枚举_cover_enum{_cover_none=0,_cover_water,//海_cover_snow,_盖子,_cover_shift=0,_cover_mask=15,};DWORD _cover[_covers]={//RRGGBB0x00000000,//无0x00003080,//瓦特(海)0x00EEEEEE,//雪};枚举_terrain_enum{_terrain_dirt=0,_terrain_sand,_terrain_rock,_terrain_water,//溪流、河流、湖泊_terrain_temp,//温度_地形,_terrain_shift=4,_terrain_mask=15,};DWORD _terrain[_terrains]={//RRGGBB0x00301510,//污垢0x00EEC49A,//沙子0x006F6F6F,//摇滚0x00006080,//水(溪流、河流、湖泊)0x00006080,//温度};枚举_flora_enum{_flora_none=0,_flora_grass,_flora_hardwood,_flora_evergreen,_flora_deadwood,_植物群,_flora_shift=8,_flora_mask=15,};DWORD _flora[_floras]={//RRGGBB0x00000000,//无0x007F7F3F,//草0x001FFF1F,//硬木0x00007F00,//常青树0x007F3F1F,//枯木};//变量浮动a,b,da;国际 c,t,f;int x,y,z,xx,yy,mxs,mys,dx,dy,dx2,dy2,r,r2,ix,l;int xh1,yh1;//最高峰位置int **ter=NULL,**typ=NULL;随机化();//将分辨率调整为 2 的幂对于 (mxs=1;mxs+1<_xs;mxs<<=1);如果(mxs<3)mxs=3;对于 (mys=1;mys+1<_ys;mys<<=1);如果 (mys<3) mys=3;ter=new int*[mys+1];对于 (y=0;y<=mys;y++) ter[y]=new int[mxs+1];typ=new int*[mys+1];对于 (y=0;y<=mys;y++) typ[y]=new int[mxs+1];//[地形]为了 (;;){//钻石 &方形随机高度图 ->三[][]dx=mxs;dx2=dx>>1;r=(mxs+mys)<<1;//初始化步、半步和随机性dy=mys;dy2=dy>>1;r2=r>>1;//设置角值如果(_岛){t=-r2;ter[0][0]=t;ter[0][mxs]=t;ter[mys][0]=t;ter[mys][mxs]=t;ter[dy2][dx2]=r+r;//中央山顶}别的{ter[0][0]=随机(r);ter[0][mxs]=随机(r);ter[mys][0]=随机(r);ter[mys][mxs]=Random(r);}for (;dx2|dy2;dx=dx2,dx2>>=1,dy=dy2,dy2>>=1)//细分步骤,直到填满整个图像{如果(!dx)dx=1;如果(!dy)dy=1;//钻石(跳过第一个岛屿)如果 ((!_island)||(dx!=mxs))对于 (y=dy2,yy=mys-dy2;y<=yy;y+=dy)对于 (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;//正方形对于 (y=dy2,yy=mys-dy2;y<=yy;y+=dy)对于 (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)+随机(r)-r2;对于 (y=dy ,yy=mys-dy ;y<=yy;y+=dy)对于 (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)+随机(r)-r2;对于 (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=我的;ter[y][x]=((ter[y][x-dx2]+ter[y][x+dx2]+ter[y-dy2][x])/3)+Random(r)-r2;}对于 (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;}如果(_岛){//在第一次通过后重新计算中间位置,这样可以有更多的中央山丘if (dx==mxs) ter[dy2][dx2]=Random(r2);//将边框调整为underwatter对于 (y=0;y<=mys;y+=dy2) { ter[y][0]=t;ter[y][mxs]=t;}对于 (x=0;x<=mxs;x+=dx2) { ter[0][x]=t;ter[mys][x]=t;}}//调整随机性r>>=1;如果(r<2)r=2;r2=r>>1;}//重新缩放到<h0,h1>xx=ter[0][0];yy=xx;对于 (y=0;y<=mys;y++)对于 (x=0;x<=mxs;x++){z=ter[y][x];如果(xx>z)xx=z;如果 (yyh_water) l++;如果 (ter[mys][x]>h_water) l++;}for (y=0;y<=mys;y++) { if (ter[y][0]>h_water) l++;如果 (ter[y][mxs]>h_water) l++;}如果(l>1+((mxs+mys)>>3))继续;}休息;}//[表面]对于 (y=0;y=h_snow) c=_cover_snow;t=_terrain_dirt;如果 (z<=h_sand) t=_terrain_sand;如果 (z>=h_rock) t=_terrain_rock;如果 (a>=a_rock) t=_terrain_rock;f=_flora_none;如果(t==_terrain_dirt){r=随机(100);如果 (r>10) f=_flora_grass;如果 (r>50){如果 (z>h_evergreen) f=_flora_evergreen;别的{r=随机(h_evergreen);如果 (r<=z) f=_flora_evergreen;否则 f=_flora_hardwood;}}如果 (r<5) f=_flora_deadwood;}typ[y][x]=(c<<_cover_shift)|(t<<_terrain_shift)|(f<<_flora_shift);}//[河流]对于 (ix=10+Random(5),a=0.0,da=2.0*M_PI/float(ix);ix;ix--){//围绕最高峰随机开始a+=da*(0.75+(0.50*Random()));对于 (l=0;l<10;l++){b=随机(mxs>>3);x=xh1;x+=float(b*cos(a));y=yh1;y+=float(b*sin(a));如果 ((x<1)||(x>=mxs)) 继续;如果 ((y<1)||(y>=mys)) 继续;如果 (typ[y][x]&0x00F==_cover_water) 继续;l=-1;休息;} if (l>=0) 继续;//安全检查对于 (l=0,r2=0;;){//停在地图边缘如果 ((x<=0)||(x>=mxs-1)||(y<=0)||(y>=mys-1)) 中断;//解码生成的表面r=typ[y][x];c=(r>>_cover_shift)&_cover_mask;t=(r>>_terrain_shift)&_terrain_mask;f=(r>>_flora_shift)&_flora_mask;//到达大海时停止如果(c==_cover_water)中断;//插入河流点半径 = r2dx=x-r2;如果 (dx<0) dx=0;dx2=x+r2;如果(dx2>=mxs)dx2=mxs-1;dy=y-r2;如果 (dy<0) dy=0;dy2=y+r2;如果 (dy2>=mys) dy2=mys-1;对于 (yy=dy;yy<=dy2;yy++)对于 (xx=dx;xx<=dx2;xx++)如果 (((xx-x)*(xx-x))+((yy-y)*(yy-y))<=r2*r2)if (((typ[yy][xx]>>_terrain_shift)&_terrain_mask)!=_terrain_water)typ[yy][xx]=(typ[yy][xx]&0x00F)|(_terrain_temp<<_terrain_shift);//步到最小高程邻居dx=x;dy=y;z=h1;typ[y][x]=(typ[y][x]&0x00F)|(_terrain_water<<_terrain_shift);xx=x;yy=y;xx--;r=ter[yy][xx];if ((z>=r)&&((((typ[yy][xx]>>_terrain_shift)&_terrain_mask)!=_terrain_water)) { z=r;dx=xx;dy=yy;}yy--;r=ter[yy][xx];if ((z>=r)&&((((typ[yy][xx]>>_terrain_shift)&_terrain_mask)!=_terrain_water)) { z=r;dx=xx;dy=yy;}xx++;r=ter[yy][xx];if ((z>=r)&&((((typ[yy][xx]>>_terrain_shift)&_terrain_mask)!=_terrain_water)) { z=r;dx=xx;dy=yy;}xx++;r=ter[yy][xx];if ((z>=r)&&((((typ[yy][xx]>>_terrain_shift)&_terrain_mask)!=_terrain_water)) { z=r;dx=xx;dy=yy;}yy++;r=ter[yy][xx];if ((z>=r)&&((((typ[yy][xx]>>_terrain_shift)&_terrain_mask)!=_terrain_water)) { z=r;dx=xx;dy=yy;}yy++;r=ter[yy][xx];if ((z>=r)&&((((typ[yy][xx]>>_terrain_shift)&_terrain_mask)!=_terrain_water)) { z=r;dx=xx;dy=yy;}xx--;r=ter[yy][xx];if ((z>=r)&&((((typ[yy][xx]>>_terrain_shift)&_terrain_mask)!=_terrain_water)) { z=r;dx=xx;dy=yy;}xx--;r=ter[yy][xx];if ((z>=r)&&((((typ[yy][xx]>>_terrain_shift)&_terrain_mask)!=_terrain_water)) { z=r;dx=xx;dy=yy;}如果 ((dx==x)&&(dy==y)){//处理无效路径或需要湖!!!如果(dx>mxs>>1)dx++;否则 dx--;如果 (dy>mys>>1) dy++;否则 dy--;}x=dx;y=dy;//随长度增加河流体积l++;if (l>d_river_l*(r2+1)) { l=0;如果 (r2>_terrain_shift)&_terrain_mask)==_terrain_water)typ[y][x]=(typ[y][x]&0x00F)|(_terrain_temp<<_terrain_shift);}对于 (y=0;y<=mys;y++)对于 (x=0;x<=mxs;x++)if ((((typ[y][x]>>_terrain_shift)&_terrain_mask)==_terrain_temp)typ[y][x]=(typ[y][x]&0x00F)|(_terrain_water<<_terrain_shift);//[复制数据] 重写这部分以满足您的需求对于 (y=1;y<_ys;y++)对于 (x=1;x<_xs;x++){浮动 nx,ny,nz,x0,y0,z0,x1,y1,z1;//(nx,ny,nz) = 表面法线nx=0.0;尼=0.0;nz=ter[y][x];x0=-d_pixel;y0=0.0;z0=ter[y][x-1];x1=0.0;y1=-d_pixel;z1=ter[y-1][x];x0-=nx;x1-=nx;y0-=ny;y1-=ny;z0-=nz;z1-=nz;nx=(y0*z1)-(z0*y1);ny=(z0*x1)-(x0*z1);nz=(x0*y1)-(y0*x1);x0=1.0/sqrt((nx*nx)+(ny*ny)+(nz*nz));nx*=x0;尼*=x0;nz*=x0;//z = 环境光 + 正常阴影nz=(+0.7*nx)+(-0.7*ny)+(+0.7*nz);如果 (nz<0.0) nz=0.0;nz=255.0*(0.2+(0.8*nz));z=nz;//r = 基色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];如果 (c) r= _cover[c];如果 (f){ 如果 (c) r|=_flora[f];否则 r=_flora[f];};//海的颜色取决于深度而不是表面法线如果 (c==_cover_water) z=256-((ter[y][x]<<7)/h0);//将光照 z 应用于颜色 ryy=int(r>>16)&255;yy=(yy*z)>>8;如果 (yy>255) yy=255;r=(r&0x0000FFFF)|(yy<<16);yy=int(r>>8)&255;yy=(yy*z)>>8;如果 (yy>255) yy=255;r=(r&0x00FF00FF)|(yy<<8);yy=int(r)&255;yy=(yy*z)>>8;如果 (yy>255) yy=255;r=(r&0x00FFFF00)|(yy);//将像素设置为目标图像pic.p[y][x].dd=r;}//免费 ter[][],typ[][]for (y=0;y<=mys;y++) delete[] ter[y];删除[]三;ter=NULL;for (y=0;y<=mys;y++) delete[] typ[y];删除[] 类型;类型=空;}//---------------------------------------------------------------------------

该代码基于我的链接答案中的代码,但具有附加功能(包括河流).我对图像使用我自己的图片类,因此一些成员是:

  • xs,ys 图像的像素大小
  • p[y][x].dd(x,y) 位置的像素,为 32 位整数类型
  • clear(color) - 清除整个图像
  • resize(xs,ys) - 将图像大小调整为新的分辨率
  • bmp - VCL 封装的 GDI 位图,具有 Canvas 访问权限

您可以在Diamond&Square中调整adjust randomness来改变地形的平滑度.还可以篡改高度限制和阈值.

为了实现更多的早午餐,就像河流在集群中播种更多起点,因此它们应该及时合并成一条或更多条河流.

I am trying to procedurally generate some rivers.

I have a flat (no concept of elevation) square grid as base and want to draw a branching structure on it like shown in the image.

Can you share the steps that one may use to get that done?

I am not looking for the fastest implementation as there is no real time generation, but the simpler implementation will be prefered. Lua is my language but anything will do.

Few more things:

  1. The shape should be generated algorithmic ally.
  2. The shape should be controllable using a seed value.

解决方案

I think generating rivers is a backward approach as you would need to tweak a lot of things according to their shape later on which will be hard. I would instead create random terrain height map and extract features from it (as in the real world) which is much easier and closer to reality. In the final map you ignore the height and use flat one (if you really want a flat map). Here are few things you can extract from height map:

  1. Rivers and lakes

    by seeding random high altitude point and following it downhill to sea level or edge of map.

  2. vegetation or ground

    from slope and altitude you can determine if ground is sand,dirt,rock. If there are trees, bushes, grass or whatever.

Here look at this QA: random island generator

and some river overview:

The way you tweak the terrain generation will affect also the river shapes (no need to generate just islands).

The Seeds are working also for this approach.

[Edit1] promised C++ code

This basically generate random height map and then seed and downhill follow the rivers (lakes are generated automatically if the terrain block downhill watter flow). The terrain type is also determined from slope and altitude.

//---------------------------------------------------------------------------
picture pic;
//---------------------------------------------------------------------------
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=35.0;         // [m] pixel size
    int   d_river_w=5;          // [pixel] river max width
    int   d_river_l=150;        // [pixel] river base length per width increase
    bool _island=true;

    // types
    enum _cover_enum
        {
        _cover_none=0,
        _cover_water,   // sea
        _cover_snow,
        _covers,
        _cover_shift=0,
        _cover_mask=15,
        };
    DWORD _cover[_covers]=
        {
        //  RRGGBB
        0x00000000,     // none
        0x00003080,     // watter (sea)
        0x00EEEEEE,     // snow
        };
    enum _terrain_enum
        {
        _terrain_dirt=0,
        _terrain_sand,
        _terrain_rock,
        _terrain_water, // streams,rivers,lakes
        _terrain_temp,  // temp
        _terrains,
        _terrain_shift=4,
        _terrain_mask=15,
        };
    DWORD _terrain[_terrains]=
        {
        //  RRGGBB
        0x00301510,     // dirt
        0x00EEC49A,     // sand
        0x006F6F6F,     // rock
        0x00006080,     // water (streams,rivers,lakes)
        0x00006080,     // temp
        };
    enum _flora_enum
        {
        _flora_none=0,
        _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,da; int c,t,f;
    int x,y,z,xx,yy,mxs,mys,dx,dy,dx2,dy2,r,r2,ix,l;
    int xh1,yh1;    // topest hill position
    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]
    for (;;)
        {
        // diamond & square random height map -> ter[][]
        dx=mxs; dx2=dx>>1; r=(mxs+mys)<<1;          // 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]=r+r;  // top of central hill
            }
        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;
                }
            if (_island)
                {
                // recompute middle position after first pass so there can be more central hills
                if (dx==mxs) ter[dy2][dx2]=Random(r2);
                // adjust border to underwatter
                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>>=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; xh1=x; yh1=y; }
            }
        for (y=0;y<=mys;y++)
         for (x=0;x<=mxs;x++)
          ter[y][x]=h0+(((ter[y][x]-xx)*(h1-h0))/(yy-xx));
        // test for correctness
        if (_island)
            {
            l=0;
            for (x=0;x<=mxs;x++) { if (ter[0][x]>h_water) l++; if (ter[mys][x]>h_water) l++; }
            for (y=0;y<=mys;y++) { if (ter[y][0]>h_water) l++; if (ter[y][mxs]>h_water) l++; }
            if (l>1+((mxs+mys)>>3)) continue;
            }
        break;
        }

    // [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);
        }

    // [Rivers]
    for (ix=10+Random(5),a=0.0,da=2.0*M_PI/float(ix);ix;ix--)
        {
        // random start around topest hill
        a+=da*(0.75+(0.50*Random()));
        for (l=0;l<10;l++)
            {
            b=Random(mxs>>3);
            x=xh1; x+=float(b*cos(a));
            y=yh1; y+=float(b*sin(a));
            if ((x<1)||(x>=mxs)) continue;
            if ((y<1)||(y>=mys)) continue;
            if (typ[y][x]&0x00F==_cover_water) continue;
            l=-1;
            break;
            } if (l>=0) continue; // safety check
        for (l=0,r2=0;;)
            {
            // stop on map edge
            if ((x<=0)||(x>=mxs-1)||(y<=0)||(y>=mys-1)) break;
            // decode generated surface
            r=typ[y][x];
            c=(r>>  _cover_shift)&  _cover_mask;
            t=(r>>_terrain_shift)&_terrain_mask;
            f=(r>>  _flora_shift)&  _flora_mask;
            // stop if reached sea
            if (c==_cover_water) break;
            // insert river dot radius = r2
            dx=x-r2; if (dx<0) dx=0; dx2=x+r2; if (dx2>=mxs) dx2=mxs-1;
            dy=y-r2; if (dy<0) dy=0; dy2=y+r2; if (dy2>=mys) dy2=mys-1;
            for (yy=dy;yy<=dy2;yy++)
             for (xx=dx;xx<=dx2;xx++)
              if (((xx-x)*(xx-x))+((yy-y)*(yy-y))<=r2*r2)
               if (((typ[yy][xx]>>_terrain_shift)&_terrain_mask)!=_terrain_water)
                typ[yy][xx]=(typ[yy][xx]&0x00F)|(_terrain_temp<<_terrain_shift);
            // step to smalest elevation neighbor
            dx=x;   dy=y; z=h1; typ[y][x]=(typ[y][x]&0x00F)|(_terrain_water<<_terrain_shift); xx=x; yy=y;
            xx--; r=ter[yy][xx]; if ((z>=r)&&(((typ[yy][xx]>>_terrain_shift)&_terrain_mask)!=_terrain_water)) { z=r; dx=xx; dy=yy; }
            yy--; r=ter[yy][xx]; if ((z>=r)&&(((typ[yy][xx]>>_terrain_shift)&_terrain_mask)!=_terrain_water)) { z=r; dx=xx; dy=yy; }
            xx++; r=ter[yy][xx]; if ((z>=r)&&(((typ[yy][xx]>>_terrain_shift)&_terrain_mask)!=_terrain_water)) { z=r; dx=xx; dy=yy; }
            xx++; r=ter[yy][xx]; if ((z>=r)&&(((typ[yy][xx]>>_terrain_shift)&_terrain_mask)!=_terrain_water)) { z=r; dx=xx; dy=yy; }
            yy++; r=ter[yy][xx]; if ((z>=r)&&(((typ[yy][xx]>>_terrain_shift)&_terrain_mask)!=_terrain_water)) { z=r; dx=xx; dy=yy; }
            yy++; r=ter[yy][xx]; if ((z>=r)&&(((typ[yy][xx]>>_terrain_shift)&_terrain_mask)!=_terrain_water)) { z=r; dx=xx; dy=yy; }
            xx--; r=ter[yy][xx]; if ((z>=r)&&(((typ[yy][xx]>>_terrain_shift)&_terrain_mask)!=_terrain_water)) { z=r; dx=xx; dy=yy; }
            xx--; r=ter[yy][xx]; if ((z>=r)&&(((typ[yy][xx]>>_terrain_shift)&_terrain_mask)!=_terrain_water)) { z=r; dx=xx; dy=yy; }
            if ((dx==x)&&(dy==y))
                {
                // handle invalid path or need for a lake!!!
                if (dx>mxs>>1) dx++; else dx--;
                if (dy>mys>>1) dy++; else dy--;
                }
            x=dx; y=dy;
            // increase river volume with length
            l++; if (l>d_river_l*(r2+1)) { l=0; if (r2<d_river_w) r2++; }
            }
        // make merging of rivers possible
        for (y=0;y<=mys;y++)
         for (x=0;x<=mxs;x++)
          if (((typ[y][x]>>_terrain_shift)&_terrain_mask)==_terrain_water)
           typ[y][x]=(typ[y][x]&0x00F)|(_terrain_temp<<_terrain_shift);
        }
    for (y=0;y<=mys;y++)
     for (x=0;x<=mxs;x++)
      if (((typ[y][x]>>_terrain_shift)&_terrain_mask)==_terrain_temp)
       typ[y][x]=(typ[y][x]&0x00F)|(_terrain_water<<_terrain_shift);


    // [copy data] rewrite this part to suite your needs
    for (y=1;y<_ys;y++)
     for (x=1;x<_xs;x++)
        {
        float nx,ny,nz,x0,y0,z0,x1,y1,z1;
        // (nx,ny,nz) = surface normal
        nx=0.0;      ny=0.0; nz=ter[y][x];
        x0=-d_pixel; y0=0.0; z0=ter[y][x-1];
        x1=0.0; y1=-d_pixel; z1=ter[y-1][x];
        x0-=nx; x1-=nx;
        y0-=ny; y1-=ny;
        z0-=nz; z1-=nz;
        nx=(y0*z1)-(z0*y1);
        ny=(z0*x1)-(x0*z1);
        nz=(x0*y1)-(y0*x1);
        x0=1.0/sqrt((nx*nx)+(ny*ny)+(nz*nz));
        nx*=x0;
        ny*=x0;
        nz*=x0;
        // z = ambient light + normal shading
        nz=(+0.7*nx)+(-0.7*ny)+(+0.7*nz);
        if (nz<0.0) nz=0.0;
        nz=255.0*(0.2+(0.8*nz)); z=nz;
        // r = base color
        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 (f){ if (c) r|=_flora[f]; else r=_flora[f]; };
        // sea color is depending on depth not surface normal
        if (c==_cover_water) z=256-((ter[y][x]<<7)/h0);
        // apply lighting z to color r
        yy=int(r>>16)&255; yy=(yy*z)>>8; if (yy>255) yy=255; r=(r&0x0000FFFF)|(yy<<16);
        yy=int(r>> 8)&255; yy=(yy*z)>>8; if (yy>255) yy=255; r=(r&0x00FF00FF)|(yy<< 8);
        yy=int(r    )&255; yy=(yy*z)>>8; if (yy>255) yy=255; r=(r&0x00FFFF00)|(yy    );
        // set pixel to target image
        pic.p[y][x].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;
    }
//---------------------------------------------------------------------------

The code is based on the code from the linked Answer of mine but with added features (rivers included). I use my own picture class for images so some members are:

  • xs,ys size of image in pixels
  • p[y][x].dd is pixel at (x,y) position as 32 bit integer type
  • clear(color) - clears entire image
  • resize(xs,ys) - resizes image to new resolution
  • bmp - VCL encapsulated GDI Bitmap with Canvas access

You can tweak the adjust randomness in Diamond&Square to change the terrain smoothness. Also the height limits and tresholds can be tampered with.

To achieve more brunching like rivers seed more start points in clusters so they should merge in time into single or more rivers.

这篇关于如何在方形网格上创建分支静脉/河流状结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆