使用柏林噪声生成游戏地图(一维和二维实现)

😁大家好,我是CuddleSabe,目前大四在读,深圳准入职算法工程师,研究主要方向为多模态(VQA、ImageCaptioning等),欢迎各位佬来讨论!
🍭我最近在有序地计划整理CV入门实战系列NLP入门实战系列。在这两个专栏中,我将会带领大家一步步进行经典网络算法的实现,欢迎各位读者(da lao)订阅🍀

导学

自然界中很多事物是分形的。它们有着很多层次细节。最平常的例子是山峰轮廓。它包含着高度上的很大变化(山峰),中等变化(丘陵),小的变化(砾石),微小变化(石头)…你可以继续想象。观察几乎所有事物:片状分布于田间草,海中的波浪,蚂蚁的运动方式,树枝的运动,大理石的花纹,风。所有这些现象表现出了同一种的大小的变化形式。柏林噪声函数通过直接添加一定范围内,不同比例的噪声函数来重现这种现象。

白噪声

当我们使用随机数去填充一个二维数组的时候,我们会得到一个如下的白噪声:
在这里插入图片描述
白噪声看起来就像电视机上面的雪花一样,其中不包含任何信息,没有办法达到我们用来生成地图的需求。

回顾正弦函数的一些定义

我们针对正弦函数有如下定义,还记得吗:

  • 振幅 (amplitude)
  • 频率 (frequency)
  • 波长(wavelength)

相信对于诸如sin,cos等周期函数的上面定义,大家已经很熟悉了。但是有一个问题:针对非周期函数,我们如何定义上述参数?
这里我们针对非周期函数做出如下参数定义:

  • 振幅 (amplitude):所使用的随机函数理论上能生成的最大值
  • 频率 (frequency) :分周期函数的采样点的间隔
  • 波长(wavelength):频率的倒数

生成噪声曲线的过程

在这里插入图片描述

其中的采样如上图所示,在生成随机函数曲线之前,我们需要获得一些采样点(一般为均匀间隔,可以使用整数);在获得采样点之后,我们再对函数进行非线性插值获得一个光滑的曲线。注意,我们现在只获得了一个曲线而不是柏林噪声,我们仍需要继续生成不同频率和振幅的曲线并将它们相加才能获得我们最终想要的东西(神奇的分形思想!!

总过程描述如下(以一维为例):

均匀采样获得采样点
确定频率和振幅参数
使用获得的参数对采样点进行随机数赋值
得到一条函数曲线
将所有函数曲线相加

一维柏林噪声

经过上述过程描述,相信大家已经对其思想有一个基本了解了。但我们仍需确定一件事情:如何确定频率和振幅参数?
这里我们定义一个新的参数:Persistence(持续度)(0-1)
我们给持续度赋值后,可以得到:

  • 频率 = 2 i 2^i 2i
  • 振幅 = 持 久 度 i 持久度^i i
    其中 i i i代表了现在是生成的第几条函数。
    可以看到,随着 i i i的增大,振幅会越来越大,函数的频率也会越来越高,波峰越来越小。且持久度越小,最后得到的结果总体波动较小。可视化结果如下:
    在这里插入图片描述
    我们将其相加,得到最终结果:
    在这里插入图片描述
    可以看到,一开始生成的几条曲线振幅较大,频率较小。如果将其比作山的话,其代表了山的总体趋势。而后面的几条曲线则分别代表了诸如小山谷、石头等变化较小的部分。

经过上述分析,我们现在编写一维柏林噪声的代码。

start = 0
end = 10
persistence = 1/2
fineness = 0.001
layer_num = 6
def cubic_interpolate(input_x, input_y, fineness, frequent, amplitude):
    x = []
    y = []
    length = len(input_x)
    cubic_func = interp1d(input_x, input_y, kind = 'cubic')
    num = int((end - start)/ fineness)
    for inter_x in list(np.linspace(start, end, num)):
        inter_y = cubic_func(inter_x)
        x.append(inter_x)
        y.append(inter_y)
    return x, y
plt.figure( figsize=(30,20) )
perlin_y = list(np.zeros(int((end-start)/fineness)))

for i in range(layer_num):
    plt.subplot(2, 3, i+1)
    amplitude = persistence**i
    frequent = 2**i
    wavelength = 1 / frequent
    num = int((end - start)/ wavelength + 1)
    x = np.linspace(start, end, num)
    y = []
    for index, data in enumerate(x):
        random.seed(data)
        noise_y = random.uniform(0, amplitude)
        y.append(noise_y)
    cubic_x, cubic_y = cubic_interpolate(x, y, fineness, frequent, amplitude)
    layer_smooth_func = interp1d(cubic_x, cubic_y, kind = 'cubic')
    for index, perlin_x in enumerate(list(np.linspace(start, end, int((end-start)/fineness)))):
        perlin_y[index] += layer_smooth_func(perlin_x)
    plt.title("a={:.2f} f={:d}".format(amplitude, frequent))
    plt.scatter(cubic_x, cubic_y, s=1)
    plt.axis([start, end, -1, 1])
plt.show()
plt.title("Perlin Noise(Cubic)")
plt.scatter(list(np.linspace(start, end, int((end-start)/fineness))), perlin_y, s=1)
plt.show()

二维柏林噪声生成地图

同理,我们可以将其拓展到二维地图的生成,代码如下:

%matplotlib inline
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d
import numpy as np
import random
import cv2
persistence = 1 /2
block = 3
layer_num = 5
layers = []
for i in range(1, layer_num+1):
    layers.append(np.zeros((3**i, 3**i)))
for layer in layers:
    print(layer.shape)
def random_fill(layer, amplitude):
    for i in range(layer.shape[0]):
        for j in range(layer.shape[1]):
            layer[i][j] = random.uniform(0, amplitude)
for i, layer in enumerate(layers):
    random_fill(layer, persistence**i)
    layers[i] = cv2.resize(layer, (block**layer_num, block**layer_num), interpolation=cv2.INTER_CUBIC)
game_map = np.zeros((block**layer_num, block**layer_num))
for layer in layers:
    game_map += layer
plt.imshow((game_map*255).astype("int8"))

在这里插入图片描述

在这里插入图片描述
上述持久度参数设置为1/2,叠加层数分别为3和5。可以看出,其生成效果已经非常近似于海战游戏地图。(大家可以多调节参数看看效果w)

  • 5
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
柏林噪声算法是一种用于生成2D地图算法。它是由柏林数学家卡尔·维特所提出的。该算法的基本原理是通过一系列随机数生成器产生噪声,在二维空间中形成连续的噪声图案。 柏林噪声算法的过程可以简单概括为以下几个步骤: 1. 确定地图大小和分辨率:首先需要确定生成地图的大小和分辨率,即地图的宽度和高度,以及像素的数量。 2. 创建随机数生成器:使用随机数生成器产生随机数序列,这些随机数将用于生成噪声地图柏林噪声算法通常使用梅森旋转算法或其他类似的高质量随机数生成器。 3. 生成噪声图案:按照一定的规则和算法使用随机数生成生成噪声图案。柏林噪声算法通常使用渐变产生随机数的方法,即每个点的随机数值是由其周围点的随机数值决定的,通过对这些值进行插值计算得到最终的噪声图案。 4. 进行后处理:得到的噪声图案可能会有一些不合理或不自然的地方,需要进行后处理来修正。常见的后处理方法包括平滑、调整亮度和对比度等。 5. 输出地图:最终生成2D地图可以输出为图片文件或其他形式的图形数据,供使用者进行进一步处理或应用。 柏林噪声算法生成2D地图具有丰富的细节和真实感,可以应用于游戏开发、地理信息系统等领域。它是一种有效而常用的生成地图算法,被广泛应用于计算机图形学和计算机模拟领域。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CuddleSabe

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值