我试图使用Perlin噪音发生器来制作地图的瓷砖,但我注意到我的噪音太尖锐了,我的意思是,它有太多的高度,没有平坦的地方,他们不会# 39;看起来像山脉,岛屿,湖泊或任何东西;它们似乎太随意而且有很多峰值。
在问题的最后,需要进行更改才能解决问题。
问题的重要代码是:
1D:
def Noise(self, x): # I wrote this noise function but it seems too random
random.seed(x)
number = random.random()
if number < 0.5:
final = 0 - number * 2
elif number > 0.5:
final = number * 2
return final
def Noise(self, x): # I found this noise function on the internet
x = (x<<13) ^ x
return ( 1.0 - ( (x * (x * x * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0)
2D:
def Noise(self, x, y): # I wrote this noise function but it seems too random
n = x + y
random.seed(n)
number = random.random()
if number < 0.5:
final = 0 - number * 2
elif number > 0.5:
final = number * 2
return final
def Noise(self, x, y): # I found this noise function on the internet
n = x + y * 57
n = (n<<13) ^ n
return ( 1.0 - ( (x * (x * x * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0)
我在代码中留下了1D和2D Perlin噪音,因为可能有人对它感兴趣: (我花了很长时间才找到一些代码,所以我觉得有人会很高兴在这里找到一个例子。) 你不需要Matplotlib或NumPy来制造噪音;我只使用它们制作图表并更好地查看结果。
import random
import matplotlib.pyplot as plt # To make graphs
from mpl_toolkits.mplot3d import Axes3D # To make 3D graphs
import numpy as np # To make graphs
class D(): # Base of classes D1 and D2
def Cubic_Interpolate(self, v0, v1, v2, v3, x):
P = (v3 - v2) - (v0 - v1)
Q = (v0 - v1) - P
R = v2 - v0
S = v1
return P * x**3 + Q * x**2 + R * x + S
class D1(D):
def __init__(self, lenght, octaves):
self.result = self.Perlin(lenght, octaves)
def Noise(self, x): # I wrote this noise function but it seems too random
random.seed(x)
number = random.random()
if number < 0.5:
final = 0 - number * 2
elif number > 0.5:
final = number * 2
return final
def Noise(self, x): # I found this noise function on the internet
x = (x<<13) ^ x
return ( 1.0 - ( (x * (x * x * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0)
def Perlin(self, lenght, octaves):
result = []
for x in range(lenght):
value = 0
for y in range(octaves):
frequency = 2 ** y
amplitude = 0.25 ** y
value += self.Interpolate_Noise(x * frequency) * amplitude
result.append(value)
print(f"{x} / {lenght} ({x/lenght*100:.2f}%): {round(x/lenght*10) * '#'} {(10-round(x/lenght*10)) * ' '}. Remaining {lenght-x}.") # I don't use `os.system('cls')` because it slow down the code.
return result
def Smooth_Noise(self, x):
return self.Noise(x) / 2 + self.Noise(x-1) / 4 + self.Noise(x+1) / 4
def Interpolate_Noise(self, x):
round_x = round(x)
frac_x = x - round_x
v0 = self.Smooth_Noise(round_x - 1)
v1 = self.Smooth_Noise(round_x)
v2 = self.Smooth_Noise(round_x + 1)
v3 = self.Smooth_Noise(round_x + 2)
return self.Cubic_Interpolate(v0, v1, v2, v3, frac_x)
def graph(self, *args):
plt.plot(np.array(self.result), '-', label = "Line")
for x in args:
plt.axhline(y=x, color='r', linestyle='-')
plt.xlabel('X')
plt.ylabel('Y')
plt.title("Simple Plot")
plt.legend()
plt.show()
class D2(D):
def __init__(self, lenght, octaves = 1):
self.lenght_axes = round(lenght ** 0.5)
self.lenght = self.lenght_axes ** 2
self.result = self.Perlin(self.lenght, octaves)
def Noise(self, x, y): # I wrote this noise function but it seems too random
n = x + y
random.seed(n)
number = random.random()
if number < 0.5:
final = 0 - number * 2
elif number > 0.5:
final = number * 2
return final
def Noise(self, x, y): # I found this noise function on the internet
n = x + y * 57
n = (n<<13) ^ n
return ( 1.0 - ( (x * (x * x * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0)
def Smooth_Noise(self, x, y):
corners = (self.Noise(x - 1, y - 1) + self.Noise(x + 1, y - 1) + self.Noise(x - 1, y + 1) + self.Noise(x + 1, y + 1) ) / 16
sides = (self.Noise(x - 1, y) + self.Noise(x + 1, y) + self.Noise(x, y - 1) + self.Noise(x, y + 1) ) / 8
center = self.Noise(x, y) / 4
return corners + sides + center
def Interpolate_Noise(self, x, y):
round_x = round(x)
frac_x = x - round_x
round_y = round(y)
frac_y = y - round_y
v11 = self.Smooth_Noise(round_x - 1, round_y - 1)
v12 = self.Smooth_Noise(round_x , round_y - 1)
v13 = self.Smooth_Noise(round_x + 1, round_y - 1)
v14 = self.Smooth_Noise(round_x + 2, round_y - 1)
i1 = self.Cubic_Interpolate(v11, v12, v13, v14, frac_x)
v21 = self.Smooth_Noise(round_x - 1, round_y)
v22 = self.Smooth_Noise(round_x , round_y)
v23 = self.Smooth_Noise(round_x + 1, round_y)
v24 = self.Smooth_Noise(round_x + 2, round_y)
i2 = self.Cubic_Interpolate(v21, v22, v23, v24, frac_x)
v31 = self.Smooth_Noise(round_x - 1, round_y + 1)
v32 = self.Smooth_Noise(round_x , round_y + 1)
v33 = self.Smooth_Noise(round_x + 1, round_y + 1)
v34 = self.Smooth_Noise(round_x + 2, round_y + 1)
i3 = self.Cubic_Interpolate(v31, v32, v33, v34, frac_x)
v41 = self.Smooth_Noise(round_x - 1, round_y + 2)
v42 = self.Smooth_Noise(round_x , round_y + 2)
v43 = self.Smooth_Noise(round_x + 1, round_y + 2)
v44 = self.Smooth_Noise(round_x + 2, round_y + 2)
i4 = self.Cubic_Interpolate(v41, v42, v43, v44, frac_x)
return self.Cubic_Interpolate(i1, i2, i3, i4, frac_y)
def Perlin(self, lenght, octaves):
result = []
for x in range(lenght):
value = 0
for y in range(octaves):
frequency = 2 ** y
amplitude = 0.25 ** y
value += self.Interpolate_Noise(x * frequency, x * frequency) * amplitude
result.append(value)
print(f"{x} / {lenght} ({x/lenght*100:.2f}%): {round(x/lenght*10) * '#'} {(10-round(x/lenght*10)) * ' '}. Remaining {lenght-x}.") # I don't use `os.system('cls')` because it slow down the code.
return result
def graph(self, color = 'viridis'):
# Other colors: https://matplotlib.org/examples/color/colormaps_reference.html
fig = plt.figure()
Z = np.array(self.result).reshape(self.lenght_axes, self.lenght_axes)
ax = fig.add_subplot(1, 2, 1, projection='3d')
X = np.arange(self.lenght_axes)
Y = np.arange(self.lenght_axes)
X, Y = np.meshgrid(X, Y)
d3 = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=color, linewidth=0, antialiased=False)
fig.colorbar(d3)
ax = fig.add_subplot(1, 2, 2)
d2 = ax.imshow(Z, cmap=color, interpolation='none')
fig.colorbar(d2)
plt.show()
问题是输出似乎不适合地图。
使用以下方式查看此输出:
test = D2(1000, 3)
test.graph()
我正在寻找更顺畅的东西。
在2D噪音中我很难注意到我在谈论的内容,但在一维中它更容易:
test = D1(1000, 3)
test.graph()
来自互联网的噪音功能稍微小一些,频率较低的峰值,但它仍然有太多。我正在寻找更顺畅的东西。
P.S:我是基于this pseudocode制作的。
即使数值较低,它也有峰值,没有曲线或平滑/平坦的线条。
感谢geza's suggestions我找到了解决问题的方法:
def Perlin(self, lenght_axes, octaves, zoom = 0.01, amplitude_base = 0.5):
result = []
for y in range(lenght_axes):
line = []
for x in range(lenght_axes):
value = 0
for o in range(octaves):
frequency = 2 ** o
amplitude = amplitude_base ** o
value += self.Interpolate_Noise(x * frequency * zoom, y * frequency * zoom) * amplitude
line.append(value)
result.append(line)
print(f"{y} / {lenght_axes} ({y/lenght_axes*100:.2f}%): {round(y/lenght_axes*20) * '#'} {(20-round(y/lenght_axes*20)) * ' '}. Remaining {lenght_axes-y}.")
return result
其他修改是:
Z = np.array(self.result)
代替图表函数中的Z = np.array(self.result).reshape(self.lenght_axes, self.lenght_axes)
。math.floor()
和import math
个变量的round()
函数中使用Interpolate_Noise
(记住round_x
)代替round_y
。return
(第二个)中的Noise
行修改为return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0)
。
D2(10000, 10)
现在唯一奇怪的是山(黄色)总是在同一个地方,但我认为这是改变Noise
函数中数字的问题。答案 0 :(得分:5)
我在你的代码中发现了这些错误:
Interpolate_Noise
参数乘以&#34;缩放&#34;进入地图(例如,将x
与0.01
相乘)。如果你在1D的情况下这样做,你会发现生成的函数已经好多了x
和x
。x
而不是n
round
代替math.floor
。这是我的答案,使用类似Perlin的简单(C ++)实现(它不是正确的perlin)噪音:https://stackoverflow.com/a/45121786/8157187
答案 1 :(得分:1)
您需要实施更积极的平滑算法。最好的方法是使用Matrix Convolution。它的工作方式是,你有一个矩阵,我们称之为&#34;内核&#34;应用于网格中的每个单元格,创建一个新的转换数据集。示例内核可能是:
0.1 0.1 0.1
0.1 0.2 0.1
0.1 0.1 0.1
假设您有这样的网格:
2 4 1 3 5
3 5 1 2 3
4 9 2 1 2
3 4 9 5 2
1 1 3 6 7
并说我们想将内核应用到最中心的2
,我们会以内核的形状切出网格,并将每个单元格与其对应的内核单元格相乘:
. . . . .
. 5 1 2 . 0.1 0.1 0.1 0.5 0.1 0.2
. 9 2 1 . x 0.1 0.2 0.1 = 0.9 0.4 0.1
. 4 9 5 . 0.1 0.1 0.1 0.4 0.9 0.5
. . . . .
然后我们可以将所有这些值相加以得到单元格的新值0.5+0.1+0.2+0.9+0.4+0.1+0.4+0.9+0.5 = 4
,然后在新数据集上填充该空格:
? ? ? ? ?
? ? ? ? ?
? ? 4 ? ?
? ? ? ? ?
? ? ? ? ?
......正如您可以想象的那样,我们必须为网格中的每个其他空间重复此操作,以便填写我们的新数据集。完成后,我们将丢弃旧数据并将此新网格用作数据集。
这样做的好处是可以使用大量内核来执行非常大的平滑操作。例如,您可以使用5x5或9x9大小的内核,这样可以使您的噪音更加平滑。
还有一点需要注意,内核需要构建,以便所有单元格的总和为1,否则你不会有质量守恒(可以这么说;例如,如果总和> 1,那么峰值往往会更高,数据的平均值会更高)。 5x5矩阵的一个例子是:
0.010 0.024 0.050 0.024 0.010
0.024 0.050 0.062 0.050 0.024
0.050 0.062 0.120 0.062 0.050
0.024 0.050 0.062 0.050 0.024
0.010 0.024 0.050 0.024 0.010
确保这种质量的一种方法就是简单地规范矩阵;将每个细胞除以所有细胞的总和。 E.g:
1 4 16 4 1 0.002808989 0.011235955 0.04494382 0.011235955 0.002808989
4 16 32 16 4 0.011235955 0.04494382 0.08988764 0.04494382 0.011235955
16 32 64 32 16 (sum = 356) --> 0.04494382 0.08988764 0.179775281 0.08988764 0.04494382
4 16 32 16 4 0.011235955 0.04494382 0.08988764 0.04494382 0.011235955
1 4 16 4 1 0.002808989 0.011235955 0.04494382 0.011235955 0.002808989
答案 2 :(得分:0)