【Unity是个好游戏】随机地形生成

前文提要

【Unity是个好游戏】我想玩什么

1.高度图

首先我们需要了解地形数据的表示方法。一般我们会用高度图来表示,高度图即一张每个像素点为高度的 bitmap。可以看到下面这张图是全球的高度图,他的位深为 8bit。

Heightmap of Earth’s surface

如果有兴趣可以从 wikipedia 上下载原图,$21600*10800$ 大小的高度图仅 5.89M。对于这么大一张 Heightmap,我们是无法直接用的,需要对他进行切割,分块加载。每个像素点之间的距离是

本次随机地形生成,高度图也会随机生成出来使用,当然随机生成的小模块也能替换为加载已有地形。

高度图的渲染效果,下图为生成的 mesh:

Heightmap

Heightmap

2.高度图随机生成

随机生成在一般的单值用法里,各个语言的Random库就有很好的支持。但对于地形图,他需要一个在2D 平面上连续的值。最简单的我们可以通过 $h=x+y$ 来遍历像素点生成高度图,这样简单地函数有利于我们在地形区块拼接不上时快速找到问题,当然也可以换成更单调的$h = x$ 或$h = y$ 来查看两轴上的拼接问题。

在 Minecraft 地图采用 Perlin 噪声 生成。他会生成类似于以下的图像:

Perlin Noise

将此图渲染成 mesh 就能得到我们想要的随机地形。

Perlin 噪声较为连续,单一使用它会导致地形过于贫乏,因此在实际生成时会多层噪声叠加。

接下来讲解的图来源于YouTube 大佬的地图生成教程 —— Procedural Terrain Generation 。这里简单的采用三层噪声进行讲解:

  • 大地形:通过对噪声密集采样,获取较为平缓的波形;
  • 巨石:通过对噪声的中等密度采样,获取一般的波形;
  • 小石块:通过对噪声的大跨度采样,获取波动幅度最剧烈的波形;

最终将这三个波形进行叠加,就是一个不再单调的波形了。

PerlinNoise1

同时对这三种波形振幅进行一个加权,减少小石块对大地形的影响,就能得到一个比较合适的地形。

PerlinNoise2

这个教程我没看完,review 了他最终的代码,大致理解他生成地形的方法。这个教程中自建 mesh 创造地形,比我使用 Unity3D 自带的 Terrain 更为复杂和底层。

3.地块生成

上图的波形其实也挺单调的,我并不想跑了一个小时之后还是类似的地形,因此需要作出一些差别。

我们会发现在现实世界中其实是有地块划分的,平原、高原、丘陵等等。我们在游戏里也自然可以划分地块,对于不同的地块配置不同的地形参数。在划分地块的时候我们需要用到另外一个噪声—— Worley noise .

这种噪声会形成类似昆虫翅膀、细胞壁等形状。同时也广泛用于水波生成。

WorleyNoise

对这种噪声的转换,可以生成我想要的地块划分。以下使用FastNoise生成~

地块划分

4.结果预览

后续的代码,将会融合以上的地形生成和地块生成。最终在不同区域上的地形差距可以非常大。可以看到带湖泊的平原后面是多重的高山,在这张图中间的山上有一处小 bug,会在后续详细介绍。

中秋快乐