在问题的最后,需要进行修改才能修复它.
该问题的重要代码是:
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,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,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,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,octaves = 1): self.lenght_axes = round(lenght ** 0.5) self.lenght = self.lenght_axes ** 2 self.result = self.Perlin(self.lenght,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,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,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,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,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) d2 = ax.imshow(Z,interpolation='none') fig.colorbar(d2) plt.show()
问题是输出似乎不适合地图.
使用以下命令查看此输出:
test = D2(1000,3) test.graph()
我正在寻找更顺畅的东西.
也许在二维噪音中很难注意到我在说什么,但在一维中它更容易:
test = D1(1000,3) test.graph()
来自互联网的噪音功能稍微小一点,频率较低,但它仍然有太多.我正在寻找更顺畅的东西.
P.S:我是根据this pseudocode制作的.
编辑:
Pikalek:
即使值较低,它也有峰值,没有曲线或平滑/平坦的线条.
geza:解决方案
感谢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).
>在round_x和round_y变量的Interpolate_Noise函数中使用math.floor()(记住导入数学)而不是round().
>修改Noise(第二个)返回行返回(1.0 – ((n *(n * n * 15731 789221)1376312589)& 0x7fffffff)/ 1073741824.0).
D2(10000,10)
现在唯一奇怪的是山(黄色)总是在同一个地方,但我认为这是改变噪音功能中的数字的问题.
解决方法
>您需要将Interpolate_Noise参数乘以“缩放”到地图中(例如,将x乘以0.01).如果你在1D情况下这样做,你会发现生成的函数已经好多了
>将八度计数从3增加到更大(3个八度音程不会产生太多细节)
>使用振幅0.5 ^八度音程,而不是0.25 ^八度音程(但你可以使用这个参数,所以0.25本身并不坏,但它没有给出太多细节)
>对于2D情况,你需要有2个外环(一个用于水平,一个用于垂直.当然,你仍然需要有八度环).因此,您需要使用水平和垂直位置正确“索引”噪声,而不仅仅是x和x.
>完全去除平滑.柏林噪音不需要它.
> 2D噪声函数有一个错误:它在返回表达式中使用x而不是n
>在三次插值中,使用round而不是math.floor.
这是我的答案,简单的(C)实现Perlin-like(它不是正确的perlin)噪音:https://stackoverflow.com/a/45121786/8157187