Понимание Perlin Noise

31

Я играю с Perlin Noise после некоторой работы с Diamond Square. Я следил за реализацией Хьюго Элиаса, которая в основном создает серию функций с x, y в качестве входных данных для выдачи каждого значения координаты.

Мой код PHP здесь :

У меня есть два вопроса:

Как использовать алгоритм для генерации карты высот в массиве? Я не совсем понял это и просто портировал на PHP псевдокод, но выполнил последнюю функцию (map_perlined) после прочтения где-то, что алгоритм «волшебным образом» дает вам переходные значения для каждой заданной точки x, y (очевидно, без необходимости читать ее смежные значения), я просто получаю это при использовании в качестве случайной функцииmt_rand(-100,100)/100;

введите описание изображения здесь

И это при использовании криптографии: 1.0-(($n*($n*$n*15731+789221)+1376312589)&0x7fffffff)/1073741824.0;(что, кстати, может быть реализовано «как есть» в PHP?):

введите описание изображения здесь

Итак, подводим итоги, три вопроса:

  1. Мой код правильный?
  2. Случайная функция может быть перенесена в PHP, как описано в коде? Не выдает ошибок, но результатов нет.
  3. Как мне на самом деле использовать алгоритм?

ОБНОВИТЬ

Хорошо, сделал порт PHP из кода, показанного в статье Густавсона, и, как сказал другой кодер, он просто генерирует одну октаву. Есть какой-нибудь другой полезный сайт / бумага / руководство о том, как использовать это с понятиями нескольких октав, амплитуды, частоты и т. Д. Для управления функцией шума? На бумаге Густавсона просто показаны результаты, а не фактическая реализация алгоритма, возможно, я что-то упустил?

ОБНОВЛЕНИЕ 2
@NATHAN

Я сделал что-то вроде:

$persistence = 0.5;

for ($j = 0; $j < $size; $j++) {
    for ($i = 0; $i < $size; $i++) {

        for ($o = 0; $o < 8; $o++) {
            $frequency = pow(2,$o);
            $amplitude = pow($persistence, $o);
            $value += SimplexNoise($i*$frequency, $j * $frequency) * $amplitude;
            }

            //$value = SimplexNoise($i, $j) + 0.5 * SimplexNoise($i, $j) + 0.25 * SimplexNoise($i, $j);
            $this->mapArray[$i][$j] = new Cell($value);

И после нормализации значений до 0..1 я получаю довольно скучную карту высот, такую ​​как:

введите описание изображения здесь

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

ОБНОВЛЕНИЕ 3

Больше работы Перлина. Я еще не нашел способ, чтобы направить шум к моим результатам. Проверьте эти октавы и конечный результат:

Октава I в IV

Octave1Octave2Octave3Octave4

Подвела

Октавы 1-4 суммируются

Каждая октава почти одинакова. Проверьте код:

$persistence = 0.5;

    for ($j = 0; $j < $size; $j++) {
      for ($i = 0; $i < $size; $i++) {
        $value = 0;

        for ($o = 0; $o < 4; $o++) {
          $frequency = pow(2,$o);
          $amplitude = pow($persistence, $o);
          $value += improved_noise($i*$frequency, $j*$frequency, 0.5)*$amplitude;

        }
        $this->map[$i][$j] = new Cell($value);

Результаты нормализованы. Что бы вы использовали, чтобы оказать сильное влияние на развитие шума? Я вижу примеры, когда изменение амплитуды дает мягкие или шероховатые поверхности, но даже если я даю огромную амплитуду, я вижу небольшую разницу.

Габриэль А. Зоррилья
источник
Просто сложите несколько экземпляров, увеличивая частоту и уменьшая амплитуду каждый раз, например: perlin (x) + 0.5 * perlin (2 * x) + 0.25 * perlin (4 * x) + ... (для стольких октав, сколько вы хотите). Вы также можете попробовать изменить факторы, чтобы получить разные взгляды; они не должны быть степенями 2
Натан Рид
1
После обновления кажется, что вы не масштабируете Y правильно - я слишком устал, чтобы впитывать PHP (так как я не знаю PHP); но я столкнулся с аналогичной проблемой на своем родном языке при реализации Perlin в первый раз. Также убивайте октавы и просто отлаживайте один уровень perlin.
Джонатан Дикинсон
Кто-нибудь для моего III обновления?
Габриэль А. Зоррилья

Ответы:

28

То, что вы реализовали, - это не шум Перлина. Я не уверен, почему Хьюго Элиас так говорит, но он в замешательстве. Вот эталонная реализация Кена Перлина. На самом деле он не вызывает никакого внешнего генератора случайных чисел, но использует встроенную хеш-функцию для получения псевдослучайных векторов градиента.

Также обратите внимание, что шум Перлина состоит только из одной октавы. Суммирование нескольких октав (масштабированных экземпляров шумовой функции), как предполагает Хьюго Элиас, является полезной техникой, но не частью шума Перлина. То, что вы получаете, это называется фрактальным шумом, иногда «фрактальным броуновским шумом» (из-за предполагаемого сходства с броуновским движением).

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

Натан Рид
источник
2
+1 за статью Густавсона. Это объясняет как перлин, так и симплексный шум самым ясным способом, который я видел до сих пор. Очевидно, простые правила шума!
FxIII
Я также нашел эту бумагу некоторое время назад, но Хьюго выглядел более простым. Я прочитаю и попробую! Благодарность!
Габриэль А. Зоррилья,
2
будьте осторожны при загрузке симплексного шума, он может содержать вирус;)
bobobobo
Я знаю, что это старая тема, но говорить, что эталонная реализация не использует случайное число, неверно. При инициализации библиотеки (или при первом вызове шумовой функции) генерируется 256 случайных градиентов. Хэширование, на которое вы ссылаетесь, просто приводит бесконечный набор целых чисел в кешируемый диапазон [0, 255]. По сути, это всего лишь оптимизация справочной таблицы, и алгоритм работает так же хорошо, если, например, вы заполняете PRNG с координатой сетки и используете его для генерации градиента, в этом случае он (намного) медленнее.
bcrist
@bcrist Я думаю, вы имеете в виду старую версию шума Перлина. «Улучшенный шум» Перлина, с которым я связан , использует фиксированный набор из 12 градиентных векторов, а не 256 случайных. Он использует таблицу перестановок в качестве хэш-функции для отображения координат сетки на один из этих 12 векторов градиента.
Натан Рид
11

Это распространенное заблуждение. То, что Уго Элиас называет "шумом Перлина", на самом деле является фрактальным, или розовым, шумом. Чтобы лучше понять, что такое шум Perlin, вы можете прочитать статью Perlin, связанную в ответе Натана Рида, или документы libnoise (там та же ошибка: шум Perlin - это то, что они называют градиентным шумом), или документы CoherentNoise .

Теперь, чтобы действительно ответить на ваш вопрос: вы не получили ожидаемый результат, потому что частота шума слишком высока. Ваши частоты начинаются с 1 и увеличиваются, что означает, что каждый пиксель в получающейся карте имеет случайное значение. Чтобы увидеть более тонкую структуру карты, вам нужно «увеличить» шум. Я действительно не говорю на PHP, но я полагаю, что код должен выглядеть следующим образом:

$arrayMap[$i][$j] = PerlinNoise_2D($i/$width, $j/$height, $p, $octaves);

То есть вы «растягиваете» один период шума по всей вашей карте. Конечно, вы можете использовать другие коэффициенты - просто попробуйте другие, посмотрите, что получится.

Не берите в голову
источник
Спасибо за последовательный шум документов! Я вижу, что вы написали это :) В чем ошибка в libnoise docs? Разве шум Перлина не является градиентным шумом?
legends2k