Шум Перлина: Разбор алгоритма

Шум Перлина — это мост между математикой и природой. Он дает нам инструмент для создания бесконечно разнообразных миров и реалистичных природных эффектов. Он перевернул представления о компьютерной графике и принёс своему создателю Оскар. Давайте разбираться, что это такое и как устроен.

Что такое шум Перлина и зачем он нужен?

Представьте, что вы разрабатываете игру и вам нужно создать:

  • Реалистичный горный ландшафт
  • Плавно движущиеся облака
  • Текстуру дерева или мрамора
  • Эффект пламени костра
  • И т.д.

Если использовать обычный случайный шум (как «снег» на старом телевизоре), получится резкая, неестественная картина. Именно эту проблему решил Кен Перлин в 1983 году, создав алгоритм, который генерирует «естественную случайность».

Шум Перлина — это математический способ создать цифровую природу, где хаос выглядит гармонично и реалистично.

Как сам Перлин описывает своё изобретение:

«Природа полна шумов, но не случайных — в ней есть структура. Вода течёт по руслам, горные хребты формируются тектоникой… Мой шум — это попытка уловить эту скрытую математику природы»
— Ken Perlin, ACM Turing Award Lecture (2021)

История создания

Кен Перлин — создатель алгоритма

Интересный факт: шум Перлина родился в голливудских спецэффектах. Компьютерные изображения того времени не выдерживали никакой критики. Неестественные и ресурсоёмкие картинки выбесили режиссёра фильма «Трон» (1982 год) настолько, что он был вынужден отыскать Кена Перлина и поставить перед ним задачу:

  • Создать реалистичные текстуры поверхностей
  • Избежать ручной прорисовки каждого кадра
  • Сэкономить вычислительные ресурсы

И Кен Перлин решил её! За это революционное решение Перлин получил технического «Оскара» в 1997 году. Его алгоритм стал фундаментом компьютерной графики.

Алгоритм генерации шума Перлина

Шаг 1: Сетка векторов (градиентов)

Представьте лист миллиметровки, наложенный на изображение. В каждой точке пересечения линий (узле сетки) мы размещаем cлучайный вектор (градиент) — «стрелочку» с направлением, длина которого всегда должна быть равна 1.

Сетка с градиентами в каждой точке

Генерация сетки случайных градиентов

Векторы направлены куда угодно, но их длина равна 1 (sin2α + cos2α = 1).

В улучшенном алгоритме Перлина 2002 года длина векторов может быть больше единицы, направление векторов либо по линиям сетки, либо по диагонали ячейки. Но сути это не меняет.

Шаг 2: Точка в ячейке сетки

Точка P в окружении четырех узлов сетки

Для любой точки P с координатами (x,y):

  1. Находим 4 ближайших узла сетки (G00, G10, G01, G11)
  2. Вычисляем вектора от каждого узла до точки P

Шаг 3: Скалярные произведения

Для каждого узла ячейки:

  • Берем градиент узла
  • Умножаем на вектор до точки P
  • Получаем значение влияния узла на точку

Во избежание вопросов, откуда взялось (Dx-1), вот простой вывод:

X1=X0+1 => X-X1 = X-X0-1 = Dx-1

Шаг 4: Плавное смешивание

Теперь нужно интерполировать эти четыре значения, чтобы получить некое средневзвешенное значение. Используем простую линейную интерполяцию:

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

Для этих целей используем  функцию плавного затухания (fade):

f(t) = 6t⁵ - 15t⁴ + 10t³

Эту функцию предложил Кен в своей статье по поводу улучшения алгоритма, поэтому нет смысла оспаривать мастера.

Таким образом, интерполяция в своём окончательном виде, будет выглядеть так:

Сетка векторов: Пояснения

Представьте, что вы художник и хотите нарисовать холмистый пейзаж. Вам нужно, чтобы холмы плавно переходили друг в друга, без резких скачков. Как этого добиться математически?

Сетка как основа

Пространство разбивается на сетку из ячеек (квадратов или кубов в 3D). В каждой вершине сетки (узле) размещается случайный вектор единичной длины — как стрелка компаса, указывающая в произвольном направлении.

Векторы задают «уклон»

Каждый вектор в узле сетки определяет, как будет изменяться значение шума в окрестностях этой точки. Представьте, что вектор — это направление наибольшего подъёма холма. Если два соседних вектора направлены навстречу друг другу — между ними образуется «долина», если в одну сторону — «склон».

Интерполяция для гладкости

Для любой точки внутри сетки (например, где-то посередине между узлами) алгоритм вычисляет влияние всех окружающих её векторов. Сначала он смотрит, как каждый из четырёх ближайших векторов (в 2D) «тянет» значение в своей зоне, затем плавно смешивает (интерполирует) эти влияния. Именно интерполяция обеспечивает плавные переходы.

Результат

Благодаря такой структуре, шум Перлина не имеет явных повторяющихся паттернов и выглядит как природные образования. Сетка векторов — это «скелет», который придаёт шуму упорядоченную случайность.

Почему именно векторы?

Градиенты: Векторы в узлах — это градиенты (направления роста). Они указывают, в какую сторону значение шума должно увеличиваться быстрее всего.

Скалярное произведение: Влияние вектора на точку вычисляется через скалярное произведение вектора градиента и вектора смещения от узла до точки. Это даёт значение «схожести направлений»: если точка лежит в направлении вектора — значение положительное, если против — отрицательное.

Контролируемая случайность: Случайные векторы гарантируют, что каждый запуск генератора создаёт уникальную текстуру, но при этом сетка обеспечивает согласованность значений в соседних точках.

Онлайн: Как работает сетка векторов

Информация по ячейке
Координаты ячейки (x, y):
Значение шума:
Градиентные векторы:
Скалярные произведения:
Интерполированные значения:
Перемещение: Ctrl +

[свернуть]

Фрактальная схема

Фрактальная схема отвечает за уровень детализации шума. Её физический смысл в следующем. В природе, на каком бы приближении от объекта не находился, всегда есть свой уровень детализации. Видим гору с самолёта — это общий вид, с земли — видим камни и мох, через лупу — видим текстуру камней. Фрактальная схема делает то же самое с шумом. Это как вложить несколько «уровней приближения» в один алгоритм.

Как это работает в нашем случае. Берем базовый шум Перлина — это наш «вид из самолета», крупные формы. Затем добавляем уменьшенные копии, приближаемся к объекту.

Каждая следующая копия:

  • В 2 раза детализированнее (частота ×2)
  • В 2-4 раза слабее (амплитуда ÷ persistence)

А потом складываем слои:
Общий шум = Слой1 + Слой2 + Слой3 + …

Такие слои принятой называть октавой. Октава шума — это звучит стильно!

В коде выглядит так:

Природа фрактальна: ветка похожа на дерево, камень — на гору. Фрактальный шум повторяет этот принцип. Количество октав зависит только от желаемого результата. Хотите плавные облака? 3 октавы. Резкие скалы? 8 октав.

Именно благодаря этому, алгоритм 1983 года до сих пор создает самые реалистичные ландшафты в играх и кино. Это не просто математика — это поэзия, воплощенная в коде.

«Перлин показал, что красота природы может быть выражена через элегантную математику» — Джон Кармак, сооснователь id Software

Онлайн: Попробуйте сами!

Ниже живая демонстрация шума Перлина. Поиграйте с параметрами:

Оригинальный Алгоритм Перлина

Кен Перлин опубликовал улучшенный алгоритм генерации в 2002 году и теперь мы все на него ориентируемся. Алгоритм представлен сразу для 3-х координат (X,Y,Z). Приведу оригинал для java:

Java Perlin Noise 2002

This code implements the algorithm I describe in a corresponding SIGGRAPH 2002 paper.

[свернуть]

Принципиально всё то же самое. Отличие в способе генерации сетки векторов. Перлин предлагает использовать заранее сформированный массив значений от 0..255. На самом деле, подразумевается, что массив может быть любым, главное, чтобы значения не повторялись.

Подробно рассмотрим этот алгоритм в следующий раз. Не хочется безразмерно расширять статью. Сейчас всё локально — разбор основ алгоритма и основных понятий. Нюансы оригинального алгоритма и примеры — тема отдельной статьи. Подписывайтесь на телегу, все анонсы там.

Листинг и комментарии

Конечно же, предложенный класс не генерирует никаких картинок. Его задача — вернуть матрицу заказанной размерности, которая содержит некие вещественные значения шума. Потом уже делайте с этим, что хотите. Хоть облака, хоть скалы.

Класс Шум Перлина

[свернуть]

Чтобы отобразить картинку сгенерированного шума, можно поступить следующим образом. Сделать битмап заданного размера и форматом пикселя на 32 бита.

Затем где-то вызвать генерацию шума и заполнить битмап следующим образом:


Онлайн: Шум Перлина и генерация ландшафта

Настройте параметры и нажмите «Сгенерировать ландшафт». Повторное нажатие кнопки картинку не изменит — при тех же параметрах генератор шума Перлина выдаст те же самые данные. В том и прелесть шума Перлина — в предсказуемости алгоритма.

Чтобы всякий раз генерировать новый ландшафт нажмите «Случайный ландшафт». По кнопке изменится только «Seed» — будет перенастроен генератор случайных чисел и на картинке появится другой ландшафт при тех же остальных параметрах.

Глубокое море
Море
Мелководье
Пляж
Равнина
Лес
Горы
Снежные вершины


Скачать

Друзья, спасибо за внимание!

Исходник (zip) 63 Кб. Delphi XE 7

Исполняемый файл (zip) 1.09 Мб (Скомпилирован в XE 7 x64)


5 1 голос
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии