1. Размер окна (1600, 1200). Это окно разделено на сетку из ячеек 40 x 40 пикселей, поэтому сетка разбита на 40 столбцов и 30 строк. Каждая ячейка 40 x 40 далее разбивается на подсетку из подячеек размером 10 x 10 пикселей, поэтому каждая ячейка 40 x 40 имеет 16 подячеек.
2. Углу каждой ячейки присваивается случайный вектор градиента
3. Затем для каждой ячейки сетки подячейки каждой сетки будут зациклены во вложенном цикле for. Для каждой подячейки в ячейке будет рассчитываться вектор смещения между всеми углами ячейки и положением подячейки, а также вычисляться скалярные произведения между ними.
4. Скалярные произведения двух верхних угловых ячеек и двух нижних угловых ячеек затем линейно интерполируются отдельно, давая 2 значения, затем эти значения линейно интерполируются, чтобы получить 1 окончательное значение шума (билинейная интерполяция — использовалась функция Smoothstep)
5. Шаги 3–4 будут выполняться для каждой ячейки сетки и всех подъячеек ячейки, а значениям шума будет присвоено значение в оттенках серого.

Проблема в том, что между ячейками цвета по-прежнему случайны, а цвета подячеек между двумя соседними ячейками не случайны. между ними действительно есть большая корреляция/плавное сочетание. Я не слишком уверен, стоит ли просто вставлять сюда часть кода, я вставлю только основные части, но мне было интересно, не сталкивался ли кто-нибудь, кто имел дело с этим алгоритмом, с подобной проблемой.
def CreateGradientVec():
theta = uniform(0, 2 * pi)
gradient_vec = pygame.Vector2(cos(theta), sin(theta))
#Theta chooses a random angle from 0-360 degrees, since sin^2(theta) + cos^2(theta) = 1, so sin(theta) + cos(theta) = 1
#and the gradient vec will be a unit vector in a random resultant direction
return gradient_vec
def SmoothStep(t):
#Formula for smoothstep function
return 3*(t**2) - 2*(t**3)
def BilinearInterpolation(d1, d2, d3, d4, point):
point_normalized = point / CELL_SIZE #NORMALISING CANDIDATE POINT TO BE USED AS INPUT FOR SMOOTHSTEP
#point_normalized *= 0.01
#Bilinear Interpolation Formula
return lerp( lerp(d1, d2, SmoothStep(point_normalized.x)), lerp(d3, d4, SmoothStep(point_normalized.x)), SmoothStep(point_normalized.y))
def PerlinNoise(grid_cells, grid_map):
noise_values = []
for cell in grid_cells:
cell_topleft = cell.GetPos()
cell_noise_values = []
#Finds all 4 corners of a cell, as well as the corresponding gradient vector of each corner
corners = [(Vector2(cell_topleft), grid_map[cell_topleft]),
(Vector2(cell_topleft[0] + CELL_SIZE, cell_topleft[1]), grid_map[(cell_topleft[0] + CELL_SIZE, cell_topleft[1])]),
(Vector2(cell_topleft[0], cell_topleft[1] + CELL_SIZE), grid_map[(cell_topleft[0], cell_topleft[1] + CELL_SIZE)]),
(Vector2(cell_topleft[0] + CELL_SIZE, cell_topleft[1] + CELL_SIZE), grid_map[(cell_topleft[0] + CELL_SIZE, cell_topleft[1] + CELL_SIZE)])
]
for subcell in cell.GetSubCells():
dot_values = []
subcell_pos = Vector2(subcell.GetPos())
for i in range(4):
corner_pos = corners[0]
gradient_vec = corners[1]
offset_vec = (subcell_pos - corner_pos) / CELL_SIZE # Normalises offset vec so both gradient and offset vec are unit vectors
dot_values.append(offset_vec.dot(gradient_vec))
noise_value = BilinearInterpolation(dot_values[0], dot_values[1], dot_values[2], dot_values[3], subcell_pos)
noise_value = (noise_value + 1.5) / 3 #Transforms noise values, so they are not negative and greater than 1
cell_noise_values.append(noise_value)
#Creates a 2D list, where each sub-list contains the noise values for all sub-cells in a single cell
noise_values.append(cell_noise_values)
return noise_values
Мобильная версия