# 尝试实现柏林噪声
import numpy as np
import matplotlib.pyplot as plt
import random
# 存储二维坐标梯度向量的数组(x,y)
G2 = [(-0.56, -0.39), (-0.88, 0.04), (0.84, 0.35), (-0.17, -0.62), (0.53, -0.49), (0.07, -0.89), (0.11, -0.38), (0.37, 0.5), (-0.7, -0.43), (-0.75, 0.09), (0.24, 0.23), (-0.59, -0.76), (0.53, 0.57), (0.67, -0.23), (0.18, -0.24), (0.43, 0.94), (0.58, 0.46), (0.32, 0.37), (-0.32, 0.58), (0.32, 0.52), (0.48, 0.75), (-0.9, 0.37), (-0.16, -0.33), (0.04, -0.36), (0.04, 0.68), (-0.75, 0.56), (0.87, 0.5), (0.66, 0.14), (0.94, -0.83), (-0.83, 0.18), (-0.53, 0.86), (0.41, -0.24), (0.64, -0.65), (-0.55, -0.86), (0.36, 0.58), (0.02, 0.55), (-0.27, 0.42), (0.45, -0.52), (-0.53, -0.71), (-0.44, 0.91), (-0.16, 0.18), (-0.21, -0.07), (0.77, 0.53), (-0.06, -0.02), (-0.53, 0.29), (-0.29, 0.35), (-0.63, -0.22), (0.26, -0.43), (0.53, -0.99), (-0.76, 0.25), (0.1, -0.86), (-0.36, -0.71), (-0.62, 0.51), (0.23, -0.69), (0.43, -0.29), (0.06, -0.04), (0.25, 0.75), (-0.0, 0.81), (0.64, 0.82), (-0.96, 0.12), (0.36, 0.42), (0.74, 0.61), (0.24, 0.57), (-0.28, -0.08), (-0.93, 0.45), (-0.83, -0.96), (0.68, 0.43), (0.7, 0.87), (0.12, 0.19), (-0.73, 0.82), (0.51, -0.03), (0.61, -0.33), (-0.47, 0.19), (0.71, -0.61), (0.41, -0.76), (-0.85, -0.2), (-0.65, 0.69), (0.89, 0.17), (-0.26, 0.36), (-0.59, 0.09), (-0.69, -0.15), (0.62, 0.5), (0.79, 0.97), (0.24, 0.6), (0.53, 0.69), (0.48, -0.06), (-0.27, -0.72), (-0.4, 0.29), (-0.01, -0.05), (0.61, -0.92), (0.18, -0.36), (0.76, -0.15), (-0.13, 0.33), (0.17, 0.06), (0.54, -0.79), (-0.78, -0.96), (-0.02, 0.47), (-0.97, 0.38), (0.78, 0.91), (0.58, 0.74), (0.79, 0.93), (-0.94, 0.15), (0.05, 0.15), (0.24, -0.77), (0.5, 0.14), (0.67, -0.98), (0.43, 0.01), (0.67, 0.52), (0.01, 0.1), (0.73, 0.6), (0.48, -0.22), (-0.79, 0.34), (0.98, 0.23), (-0.87, -0.93), (0.41, -0.22), (-0.98, -0.07), (0.68, 0.27), (-0.64, -0.02), (0.43, 0.7), (0.36, 0.2), (0.63, 0.48), (-0.36, -0.09), (-0.6, -0.86), (0.11, -0.16), (0.57, 0.75), (0.77, 0.41), (-0.91, 0.76), (-0.01, 0.71), (-0.8, 0.74), (-0.38, 0.1), (0.12, 0.22), (-0.19, 0.88), (0.44, -0.82), (-0.01, -0.86), (0.13, 0.05), (-0.58, 0.48), (-0.56, 0.34), (0.28, -0.63), (-0.35, -0.44), (0.73, -0.4), (0.82, 0.74), (0.07, 0.93), (-0.52, 0.66), (0.86, -0.85), (-0.86, 0.9), (0.95, -0.88), (-0.09, 0.46), (0.12, -0.72), (0.24, 0.51), (0.87, 0.77), (-0.82, -0.44), (-0.17,
-0.98), (0.34, -0.21), (0.49, 0.15), (-0.85, -0.62), (0.5, -0.78), (-0.36, 0.73), (-0.42, -0.13), (-0.09, -0.65), (0.96, 0.72), (0.76, 0.12), (0.74, -0.65), (0.3, -0.01), (-0.41, 0.52), (-0.75, -0.66), (0.89, -0.39), (-0.82, 0.45), (0.98, 0.63), (0.3, -0.6), (0.83, -0.52), (-0.1, -0.78), (0.84, -0.39), (0.37, 0.38), (-0.53, -0.83), (-0.08, -0.98), (-0.95, 0.44), (-0.54, -0.4), (0.73, -0.13), (0.68, -0.44), (-0.36, -0.7), (-0.84, -0.34), (0.22, 0.54), (0.06, -0.31), (0.66, -0.71), (-0.43, 0.71), (-0.77, -0.99), (-0.54, 0.4), (-0.16, 0.97), (0.93, -0.37), (-0.0, -0.68), (0.29, 0.67), (-0.95, -0.81), (0.67, -0.53), (0.56, 0.16), (-0.26, -0.04), (-0.1, 0.5), (0.21, 0.71), (-0.76, 0.79), (0.06, 0.65), (-0.78, 0.29), (0.03, -0.68), (0.78, 0.76), (-0.75, 0.61), (-0.11, -0.58), (0.57, 0.06), (0.51, -0.2), (0.44, -0.9), (0.21, 0.22), (0.32, -0.52), (-0.38, 0.23), (0.57, 0.27), (-0.32, 0.49), (-0.09, -0.94), (0.13, 0.12), (-0.68, 0.16), (-0.11, -0.28), (-0.93, 0.62), (-0.52, 0.82), (-0.15, -0.97), (-0.83, 0.22), (0.18, 0.25), (0.06, -0.77), (0.53, 0.42), (0.73, -0.19), (-0.68, 0.38), (-0.45, -0.57), (0.75, -0.01), (-0.89, -0.1), (-0.97, 0.55), (0.24, 0.0), (-0.02, 0.65), (0.44, 0.87), (0.91, -0.51), (-0.33, -0.51), (-0.57, 0.05), (0.53, 0.68), (0.06, 0.83), (-0.46, 0.54), (-0.86, 0.46), (0.53, 0.6), (0.56, -0.76), (0.8, 0.95), (0.47, -0.24), (-0.85, -0.98), (-0.26, -0.89), (-1.0, -0.03), (0.04, 0.37), (-0.15, -0.7), (0.0, -0.69), (0.46, 0.57), (-0.47, -0.8), (0.31, 0.32), (-0.04, -0.1), (0.08, 0.82), (-0.48, 0.47), (0.64, -0.9)]
# 存储G2下表的数组P2
P2 = [149, 97, 137, 184, 58, 1, 220, 152, 41, 235, 246, 191, 36, 188, 190, 108, 222, 52, 39, 159, 104, 90, 197, 202, 5, 245, 93, 134, 157, 146, 38, 17, 124, 32, 203, 28, 106, 12, 233, 227, 77, 27, 155, 214, 114, 154, 242, 53, 139, 183, 16, 70, 130, 23, 229, 119, 101, 181, 228, 98, 230, 136, 107, 55, 225, 24, 199, 67, 34, 113, 182, 44, 215, 169, 66,
208, 247, 131, 22, 80, 100, 212, 232, 87, 221, 167, 194, 29, 14, 33, 196, 115, 19, 170, 171, 240, 150, 63, 43, 244, 111, 206, 83, 51, 85, 151, 205, 249, 9, 163, 250, 75, 164, 195, 84, 147, 237, 209, 138, 79, 176, 248, 4, 129, 82, 73, 180, 239, 30, 234, 35, 173, 236, 76, 74, 89, 125, 189, 123, 20, 117, 148, 179, 207, 48, 251, 241, 140, 26, 172,
18, 158, 92, 141, 94, 254, 71, 120, 62, 177, 186, 109, 56, 10, 226, 144, 61, 161, 72, 122, 187, 160, 49, 128, 7, 116, 68, 118, 112, 95, 238, 231, 252, 178, 166, 69, 88, 86,
255, 105, 192, 210, 0, 174, 201, 31, 185, 57, 253, 59, 243, 142, 65, 224, 217, 135, 219, 145, 25, 126, 211, 2, 102, 162, 133, 153, 213, 37, 110, 54, 96, 165, 200, 15, 3, 21, 156, 78, 64, 121, 204, 218, 198, 127, 40, 103, 91, 143, 47, 216, 175, 11, 13, 132, 60, 6, 168, 8, 223, 193, 81, 50, 42, 46, 99, 45]
def square(length, width) -> int:
'''定义单位正方形形成网格,x纵坐标为width,y横坐标为length
[A, ,B]
[ ]
[C, ,D]'''
# 存储单位正方形网格的二维数组
square_list = [[0]*length for y in range(width)]
for x in range(width):
for y in range(length):
# 定义梯度向量,存储到单位正方形中
G = G2[P2[x]+y]
square_list[x][y] = G
#Gb = G2[P2[x]+(y+1)]
#Gc = G2[P2[x+1]+y]
#Gd = G2[P2[x+1]+(y+1)]
# 返回填充完毕的单位正方形网格
return square_list*2
def dot(width, length):
'''随机生成的输入点'''
return (round(random.uniform(0, width-1), 2), round(random.uniform(0, length-1), 2))
def perlin(dots, squares) -> list:
'''计算传入点的影响值,在地形中就是海拔,dot为一个[x,y]数组
[Ga, ,Gb]
[ ]
[Gc, ,Gd]
'''
dots_influence_value = []
for num in range(len(dots)):
# 获取点的xy坐标
x = dots[num][0]
y = dots[num][1]
# 定位点所在的单位正方形
x0 = int(x//1)
y0 = int(y//1)
x1 = int(x0 + 1)
y1 = int(y0 + 1)
# 计算距离向量
distanceA = (x-x0, y-y0)
distanceB = (x-x0, y-y1)
distanceC = (x-x1, y-y0)
distanceD = (x-x1, y-y1)
# 获取四个顶点上的梯度向量
Ga = squares[x0][y0]
Gb = squares[x0][y1]
Gc = squares[x1][y0]
Gd = squares[x1][y1]
# 对各个顶点上的梯度向量和距离向量做数量积运算,就是AB*AC = |AB|*|AC|*cosΘ
# cosΘ = (AB * AC)/(|AB|*|AC|)
# |AB| = (x**2 + y**2)**0.5
#! 计算出四个顶点的影响值
valueA = (Ga[0]**2 + Ga[1]**2)**0.5 * (distanceA[0]**2 + distanceA[1]**2)**0.5 * (Ga[0]*distanceA[0]+Ga[1]*distanceA[1])/((Ga[0]**2 + Ga[1]**2)**0.5 * (distanceA[0]**2 + distanceA[1]**2)**0.5)
valueB = (Gb[0]**2 + Gb[1]**2)**0.5 * (distanceB[0]**2 + distanceB[1]**2)**0.5 * (Gb[0]*distanceB[0]+Gb[1]*distanceB[1])/((Gb[0]**2 + Gb[1]**2)**0.5 * (distanceB[0]**2 + distanceB[1]**2)**0.5)
valueC = (Gc[0]**2 + Gc[1]**2)**0.5 * (distanceC[0]**2 + distanceC[1]**2)**0.5 * (Gc[0]*distanceC[0]+Gc[1]*distanceC[1])/((Gc[0]**2 + Gc[1]**2)**0.5 * (distanceC[0]**2 + distanceC[1]**2)**0.5)
valueD = (Gd[0]**2 + Gd[1]**2)**0.5 * (distanceD[0]**2 + distanceD[1]**2)**0.5 * (Gc[0]*distanceD[0]+Gd[1]*distanceD[1])/((Gd[0]**2 + Gd[1]**2)**0.5 * (distanceD[0]**2 + distanceD[1]**2)**0.5)
#! 利用lerp和fade进行双线性插值计算,x为u,y为f
u = fade(x-x0)
v = fade(y-y0)
# 双线性插值的两个点
#! 是对四个顶点的影响值进行插值
x1 = lerp(valueA,valueB,u)
x2 = lerp(valueC,valueD,u)
# 用v进行最终输入点影响值计算
dots_influence_value.append(lerp(x1,x2,v))
return dots_influence_value
def lerp(a,b,x):
'''线性插值'''
return a + x * (b-a)
def fade(t):
'''fade函数计算u,v进行非线性差值,0<=t<=1'''
return 6 * t**5 - 15 * t**4 + 10 * t**3
length = 10
width = 5
squares = square(length, width)
# 点坐标
dots = [dot(width,length) for x in range(10)]
dots_position_x = []
dots_position_y = []
dots_num = len(dots)
for x in range(dots_num):
dots_position_x.append(dots[x][0])
dots_position_y.append(dots[x][1])
influence_value_list = perlin(dots, squares)
#!接下来就是可视化问题,如何将点的坐标和对应的影响值可视化
#plt.imshow(dots,influence_value_list)
#plt.contourf(dots_position_x,dots_position_y,influence_value_list,10)
plt.show()