Існує дві частини, щоб створити подібний шум частоти FBm. По-перше, вам потрібно зробити функцію шуму Perlin плиткою. Ось код Python для простої функції шуму Perlin, яка працює з будь-яким періодом до 256 (ви можете тривіально розширити її на скільки завгодно, змінивши перший розділ):
import random
import math
from PIL import Image
perm = range(256)
random.shuffle(perm)
perm += perm
dirs = [(math.cos(a * 2.0 * math.pi / 256),
math.sin(a * 2.0 * math.pi / 256))
for a in range(256)]
def noise(x, y, per):
def surflet(gridX, gridY):
distX, distY = abs(x-gridX), abs(y-gridY)
polyX = 1 - 6*distX**5 + 15*distX**4 - 10*distX**3
polyY = 1 - 6*distY**5 + 15*distY**4 - 10*distY**3
hashed = perm[perm[int(gridX)%per] + int(gridY)%per]
grad = (x-gridX)*dirs[hashed][0] + (y-gridY)*dirs[hashed][1]
return polyX * polyY * grad
intX, intY = int(x), int(y)
return (surflet(intX+0, intY+0) + surflet(intX+1, intY+0) +
surflet(intX+0, intY+1) + surflet(intX+1, intY+1))
Перліновий шум генерується від підсумовування невеликих "серфінгітів", які є продуктом випадково орієнтованого градієнта і роздільної функції полінома, що випадає. Це дає позитивний регіон (жовтий) та негативний регіон (синій)
Партфелі мають розмір 2х2 і орієнтовані на цілі точки решітки, тому значення шуму Перліна в кожній точці простору виробляється шляхом підсумовування серфінгу в кутах клітини, яку він займає.
Якщо змусити градієнтні напрямки обгортати з певним періодом, то сам шум потім буде плавно загортатися з тим самим періодом. Ось чому вищевказаний код приймає модуль координати решітки за період перед хешированием через таблицю перестановок.
Другим кроком є те, що підсумовуючи октави, вам потрібно буде масштабувати період з частотою октави. По суті, вам потрібно, щоб кожна октава плиткала все справедливе зображення один раз, а не кілька разів:
def fBm(x, y, per, octs):
val = 0
for o in range(octs):
val += 0.5**o * noise(x*2**o, y*2**o, per*2**o)
return val
Зберіть це разом, і ви отримаєте щось подібне:
size, freq, octs, data = 128, 1/32.0, 5, []
for y in range(size):
for x in range(size):
data.append(fBm(x*freq, y*freq, int(size*freq), octs))
im = Image.new("L", (size, size))
im.putdata(data, 128, 128)
im.save("noise.png")
Як бачите, це дійсно плитка:
Ось невелике налаштування та кольорове відображення, ось хмарне зображення, нанесене плиткою 2х2:
Сподіваюся, це допомагає!