Процедурная графика и шум
Многие природные текстуры не рисуют вручную, а вычисляют формулами — на основе плавного псевдослучайного шума.
Процедурная графика — генерация изображений и текстур алгоритмом, а не готовым файлом; основа — функции шума вроде шума Перлина.
Зачем это знать
Облака, мрамор, дерево, вода, огонь, бесконечные ландшафты — всё это можно описать формулой, которая занимает байты вместо мегабайтов и масштабируется до любой детализации. Ключ — гладкий шум: случайный, но без резких скачков, как природные узоры.
Белый шум против гладкого
Обычный случайный (белый) шум — это «телевизионная рябь»: каждое значение независимо, картинка дёрганая. Природа выглядит иначе: соседние точки похожи. Гладкий шум получают интерполяцией между случайными значениями в узлах сетки.
import random
random.seed(42)
white = [round(random.random(), 2) for _ in range(8)]
print("Белый шум: ", white)
# гладкий: случайные значения в узлах + линейная интерполяция между ними
def smooth(values, between=2):
out = []
for i in range(len(values) - 1):
a, b = values[i], values[i+1]
for k in range(between):
t = k / between
out.append(round(a + (b - a) * t, 2))
return out
nodes = [0.2, 0.8, 0.3, 0.9]
print("Узлы: ", nodes)
print("Гладкий: ", smooth(nodes, 3))
Вывод:
Белый шум: [0.64, 0.03, 0.28, 0.22, 0.74, 0.68, 0.89, 0.09] Узлы: [0.2, 0.8, 0.3, 0.9] Гладкий: [0.2, 0.4, 0.6, 0.8, 0.63, 0.47, 0.3, 0.5, 0.7]
Белый шум прыгает хаотично, а гладкий плавно перетекает между узлами — он и похож на природу.
Октавы: фрактальный шум
Один слой шума — это крупные пятна. Природа же многомасштабна: крупные холмы, на них кочки, на них рябь. Складывая несколько слоёв (октав) шума с уменьшающейся амплитудой и растущей частотой, получают богатую фрактальную текстуру (fBm).
import math
def fbm(x, octaves=4):
total = 0.0
amp = 1.0
freq = 1.0
for _ in range(octaves):
# псевдо-шум через синус (для демонстрации формы)
total += amp * (0.5 + 0.5 * math.sin(freq * x))
amp *= 0.5 # амплитуда падает
freq *= 2.0 # частота растёт
return round(total, 3)
for x in [0.0, 1.0, 2.0, 3.0]:
print(f"x={x}: fbm={fbm(x)}")
Вывод:
x=0.0: fbm=0.938 x=1.0: fbm=1.553 x=2.0: fbm=1.309 x=3.0: fbm=0.815
Складывая слои разной частоты и убывающей амплитуды, получаем неровную, но органичную кривую — основу ландшафтов и облаков.
Как работает под капотом
Шум Перлина (и более новый simplex noise) в узлах сетки хранит не значения, а случайные градиенты, и интерполирует их сглаживающей функцией — оттого он плавный и без видимой сетки. В шейдерах шум считают прямо во фрагментном шейдере по координате, получая анимированные воду и огонь без единой текстуры. Анимацию дают, прибавляя время к координате шума.
Частые ошибки
- Использовать белый шум там, где нужен гладкий — узор выйдет «грязным».
- Линейная интерполяция вместо сглаживающей — видны artefacты сетки (резкие «грани»).
- Брать слишком много октав — дорого и почти незаметно после 4–6 слоёв.
Итоги
- Процедурная графика генерирует текстуры формулой, а не файлом.
- Гладкий шум (Перлина) плавно интерполирует случайность — похож на природу.
- Сложение октав (fBm) даёт многомасштабный фрактальный узор.
- Шум в шейдере + время = анимированные вода, огонь, облака без текстур.