撰写了文章 发布于 2020-03-10 09:33:22
【奇幻地图程序生成(一)】基本海岸轮廓线
全世界人民对于奇幻故事都非常向往,如果能描绘自己的奇幻世界就太棒了。奇幻世界的基本要素除了故事,就是一张奇幻画风的地图了,或者叫Fantasy Map。
没看够?图片搜索“Fantasy Map”就能看到更多的奇幻地图。
但是手绘虽然简单,但非常耗时。于是“懒惰”的大家想出了一个办法,干脆用程序去画吧,只要轻点鼠标,一张漂亮的奇幻风格的地图就生成了。我发现比较好玩的在线奇幻生成器有
1.https://www.makeamap.cn/(非常好用,支持自定义修改)
2.https://azgaar.github.io/Fantasy-Map-Generator/
3.http://bl.ocks.org/Azgaar/b845ce22ea68090d43a4ecfb914f51bd
这些奇幻地图究竟是如何生成的呢?具体技术可以使用Javascript的SVG,或者C++生成png图片的库。不过这些不是本系列的重点,本系列主要参考了hereDragonsAround的博客,将与大家讨论如何用程序生成奇幻风格地图的内在逻辑。
这系列文章将分为六篇
好,现在开始吧。我们看到的奇幻地图可能都是某个大陆的部分,但如果一开始就绘制大陆的话非常麻烦。所以我们先从简单的岛屿开始,而地图边界自然而然地就用水域填充,岛屿是独立的,还能限制的奇幻故事发生的范围。
为了绘制岛屿的轮廓,我们先来生成一个圆。
这玩意怎么看都不像一个岛屿对吧?这个圆太标准,我们尝试重新绘制它的边界。如下图a,在圆上随机选择几个采样点,然后用直线连接这些采样点,如下图b。另一种稍微复杂一些的方法是随机生成一些在指定范围内的点,然后用凸包连接它们,如下图c。
岛屿边界直线又长又直,太难看了,好,我们把它们弄弯。如下图b,用随机函数添加几个蓝色控制点把长直线拆分成短折线。然后连接这些短折线的终点,然后用特殊的曲线算法,比如贝塞尔曲线,或者Catmull-Rom曲线。
不要被贝塞尔曲线吓到了,我们只需要用二阶贝塞尔曲线即可,比如要生成a,b之间,c为控制点的二阶贝塞尔曲线,只需要按如下方式定义即可。t从0逐渐增加1时,f会有一条圆滑的轨迹,这就是贝塞尔曲线,不过是三个一阶乘法而已。
另一个catmull-rom曲线稍微复杂一些,详细请看这篇文章。
如果之前使用凸包算法,那么到现在可能是这个样子
好了,我们有个近似圆形的轮廓线不规则的岛屿了。
如果之前使用凸包算法,那么可能就是这个样子了。
岛屿轮廓看起来还是怪怪的,对吧?特别是第一个,还是个圆嘛。
为生成不规则的轮廓。一种常见的技术是使用噪音,多次随机生成噪音并叠加,这样比较像自然景观,比如Perlin噪音,这个噪音的特点是噪音是连续的,非常适合生成连续的地形。
所谓Perlin噪音就是下图这种形状,不同的灰度代表着高度,黑色的RGB值为[0,0,0],代表着低地,白色的RGB值为[255,255,255]代表着高地。
可以在这个网站上体验Perlin噪音生成的地形,比如下面这种:
当然这就不是小岛了,那么再用不规则的圆围一圈就好了嘛。
最终成果如下:
边缘仍然太规则了,那么为边缘继续添加噪音,一种好方法就是为相邻的边缘添加相近的噪音,而不是互相独立,就能生成各种形状的边缘。伪代码如下:
效果如下:
先不要关注那些阴影与植被,但目前看来,海洋轮廓线还是不错的。
除了这些方法,还有一些其他方法,基本思想一样,先用少数控制点生成大轮廓,再继续细分,绘制出曲折的海岸线。
比如分形,使用多个分形叠加
RedBlobGame在他的文章中提到的方法是Voronoi图生成多边形地形。
Martin O'Leary在他的文章使用的方法是直接用Delaunay三角形作为边界
或者干脆看看《文明5》使用六边形生成轮廓线,下图可以看到轮廓线与六边形边界并非完全重合。
学会了生成小岛轮廓,那么生成更多岛屿轮廓自然不在话下。但是这里还有一个好玩的生成近岸群岛的方法。现在岛屿轮廓外围生成一个多边形,给这个多边形赋上地形高度,然后低于某个高度的删掉,就形成了近岸群岛了。
好了,现在我们有了一个光秃秃的岛,下面尝试为它生成一些山。