Итак, сегодня мы поговорим о генерации пещер и карт высот с помощью шума. Это будет Гауссовский шум, его легче всего сделать в Python Pillow.

На выходе мы будем получать такие изображения.
Или такие, так тоже можно.

Первые можно использовать для генерации карт высот или текстур, а вторую для генерации пещер.

Для начала расскажу, как работает алгоритм для генерации карт высот. Мы просто берем обычный пиксельный шум, а потом размываем его функией из модуля Pillow:

im1 = im1.filter(ImageFilter.GaussianBlur(radius = 3)) #im1 - картинка с пиксельным шуом

Приступим к коду.

Сначала импортируем все библиотеки и загрузим картинки.

from PIL import Image, ImageDraw, ImageFilter #Выгружаем все из модуля Pillow.
from random import * #Импортируем библиотеку random, для генерация псевдослучайных чисел)))
  
im1 = Image.new("RGB", (256, 256)) #Создаем изображение 256 на 256 пикселей.
draw = ImageDraw.Draw(im1) #Создаем холст для нашего фона.
width = im1.size[0]
height = im1.size[1] #Получаем размер фона.
pix = im1.load() #Получаем все пиксели из фона.

Теперь давайте генерировать шум!

for x in range(width): 
	for y in range(height):
		sr = randint(0, 255) #Берем случайное число.
		draw.point((x,y), (sr,sr,sr)) #И рисуем его на холсте.
    #По сути, ничего с фоном мы не делаем, нам просто нужен ImageDraw.Draw 
    #Который мы будем заполнять случайными пикселями.

теперь выведем это на экран функцией im1.show()

Получим такое изображение)))

Теперь надо размыть его.

im1 = im1.filter(ImageFilter.GaussianBlur(radius = 3))
im1.show()
Вот то, что мы получим)))

У нас теперь есть шум, который мы можем использовать))) Но еще можно доработать это, чтобы получать карты подземелий.

Для начала, мы используем для работы с изображениями RGB-представление, и 8-битную запись, а значит каждый пиксель у нас записан в виде кортежа:

(r, g, b) #Значение каждого элемента - от 0 до 255.

Чтобы сгенерировать такие пещеры, мы будем округлять значение яркости каждого пикселя. Если оно больше половины максимальной яркости - а это в 8-битной записи 255, то мы заменяем яркость у пикселя на 255. Если нет, то заменяем яркость пикселя на 0.

draw = ImageDraw.Draw(im1)
pix = im1.load() #Тут загружаем данные об размытом изображении.

for x in range(width):
	for y in range(height):
		r = pix[x, y][0] #
		g = pix[x, y][1] #Тут как когда мы генерировали пиксельный шум, поэтому
 		b = pix[x, y][2] #не буду обьяснять.


		if r > 127:
			r = 255 #
			g = 255 #Проверяем, больше ли r 127 (это 255 / 2). Проверяем именно r 
			b = 255 #Потому-что предполагается, что g и b будут ему равны, т. к. шум монохромный 
		else: 
			r = 0
			g = 0 
			b = 0



		draw.point((x, y), (r,g,b)) #Рисуем точку на холсте.

По сути все.

Еще можно в конце написать im1.save('res.png') чтобы сохранить сгенерированную карту.