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

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

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

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

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

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

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

from PIL import Image, ImageDraw, ImageFilter #Выгружаем все из модуля Pillow.
from random import * #Импортируем библиотеку random, для генерация псевдослучайных чисел)))
  
im1 = Image.open("back.png") #Загружаем фон, над которым будем генерировать шум. это просто черная картинка 160 на 160 пикселей.
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') чтобы сохранить сгенерированную карту.

Комментарии (10)


  1. DistortNeo
    21.01.2022 15:10
    +1

    Не нужно изобретать велосипеды.

    https://habr.com/ru/post/430384/

    https://habr.com/ru/post/342906/


    1. VadimCoder Автор
      22.01.2022 17:42

      Первая статья - про шум Перлина.

      Вторая - про шум Перлина.

      Как это связано с моей статьей?)

      А по итогу полный велосипед, да.


      1. DistortNeo
        22.01.2022 17:59

        Так я специально искал статьи по запросу "шум перлина", потому что он активно используется для процедурной генерации всего, чего только можно.


        1. VadimCoder Автор
          22.01.2022 18:03

          Но у меня в статье не шум Перлина, а шум Гаусса. Это вроде как не одно и то же)


          1. DistortNeo
            22.01.2022 18:06
            +1

            Ваша статья начинается со слов:

            Итак, сегодня мы поговорим о генерации пещер и карт высот с помощью шума

            Обычно для этой цели используется шум Перлина.

            Если же вы используете для этой задач другой шум (шум Гаусса), стоит обосновать, чем же он лучше. Ну либо просто признаться, что вы не изучали матчасть и придумали велосипед.


            1. VadimCoder Автор
              22.01.2022 19:33

              Признаюсь, матчасть совсем не изучал. Но других статей на эту тему (шум Гаусса для проц. генерации) не видел.


  1. berez
    21.01.2022 15:18
    +2

    Так это… Ну ладно карта высот — будут кочки, это красиво. Но карта пещер должна ведь каким-то требованиям по связности отвечать? А то получится гора, вся дырявая внутри, но при этом не имеющая ни единого прохода в глубину.


    1. Myxach
      21.01.2022 16:12
      +1

      Можно брать результат за основу, а потом уже на этой основе генерировать новую карту. Допустим связать закрытые участки(игрок в них попасть никак не может) с открытыми (в которые он может попасть)


  1. pehat
    21.01.2022 17:27
    +1

    С каких это пор заблюренный белый шум является градиентным?


    1. VadimCoder Автор
      22.01.2022 17:36

      Я ошибся, думал градиентный шум это просто шум с плавными перепадами. Уберу упоминание.