Как создать мозаичный сплошной шум для генерации карт?

16

Привет, ребята, я пытаюсь выяснить, как генерировать мозаичные фракталы в коде (для игровых карт, но это не имеет значения ) Я пытался изменить плагин Solid Noise, поставляемый с GIMP (с моим крайне ограниченным пониманием того, как код работает) но я не могу заставить мой работать правильно.

Мой модифицированный код до сих пор (Java)

Модуль чистого шума GIMP, на котором я основываю свой код (C)

Вот то, что я пытаюсь достичь, но это то, что я получаю

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

Ник Бадал
источник
попробуйте использовать бикубическую интерполяцию вместо билинейной? Я понятия не имею, если это ваша проблема, но выглядит так, как есть.
Стивен Фурлани

Ответы:

4

Я не точно следую вашему коду, но здесь приведено упрощенное описание алгоритма, который примерно достигнет эффекта (на основе изображения, которое вы разместили).

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

  1. Создайте n слоев равномерного случайного шума (только случайные пиксели в оттенках серого).
  2. Теперь сэмплируем каждый из них, отбирая каждые 1, 2, 4, 8, ... 2 ^ (n-1) пикселей и интерполируя промежуточные пиксели. Каждый слой более гладкий, чем предыдущий.
  3. Теперь масштабируйте их с коэффициентом 1, 2, 4, 8 и т. Д. Каждый слой темнее предыдущего.
  4. Добавьте все это вместе.
  5. Нормализовать, разделив каждый пиксель с (1 + 2 + 4 + 8 + ... 2 ^ (n-1)).

Сложным шагом является этап выборки и интерполяции. Предположим, что мы находимся в слое, пропускающем выборку каждого m-го пикселя. Вот основная идея для m> 1 (если m равно 1, мы используем изображение как есть):

for each pixel x and y
   left_sample_coord = m *(x / m) //(integer division, automatically truncated)
   right_sample_coord = (left_sample_point + m) % image_width
   top_sample_point = m*(y / m) 
   bottom_sample_coord = (top_sample_point + m) % image_height

   horizontal_weight = (x - left_sample_point) / (m - 1)
   vertical_weight = (y - top_sample_point) / (m - 1)

   sample_top_left = image(left_sample_coord, top_sample_point)
   //and the same for the other four corners

   //now combine the top two points
   top_interpolate = sample_top_left * horizontal_weight + sample_top_right * (1-horizontal_weight)

  //now combine the bottom two points
  bottom_interpolate = sample_bottom_left * horizontal_weight + sample_bottom_right * (1-horizontal_weight)

  //and combine these two last obtained values

  smooth_noise(x, y) = top_interpolate * vertical_weight  + bottom_interpolate * (1 - vertical_weight)

Несколько советов:

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

Кажется, что мой оригинальный pastebin истек как-то, поэтому у меня нет возможности сравнить мой нерабочий код, но в моей текущей игре я прошел и перевел GIMP-код в java снова, и теперь он, кажется, работает нормально.

Если кто-то планирует использовать этот код, я бы порекомендовал изменить конструктор, чтобы изменить параметры настройки (детали и размер), чтобы вы могли заставить его работать так, как вам хочется. РЕДАКТИРОВАТЬ: я понял, что мой первоначальный вопрос был о том, чтобы сделать его мозаичным, так что не забудьте установить tilable в true!

Код: http://pastebin.com/KsfZ99Xa

Пример: пример генератора Perlin

Ник Бадал
источник
2

Просто пролистал версии Java и C и заметил небольшую разницу в том, как вы используете функцию шума. Вот твой:

int val = Math.abs((int) Math.floor(255.0 * noise(((double)col/(double)width), ((double)row/(double)height))));

Код C:

val = (guchar) floor (255.0 * noise ((col - xoffset) / width,

                                           (row - yoffset) / height));

Почему вы решили не вычитать смещение? (col - xoffset) и (row - yoffset)

Просто интересуюсь. У меня нет времени, чтобы сделать полный анализ кода.

Надеюсь это поможет.

гвоздильщик
источник
xoffset и yoffset должны вычислять способ, которым GIMP делит изображения на сетки, но моя программа работает на одной плитке, поэтому смещение по x и y будет равно 0
Ник Бадал
2

Я не знаю, может ли это помочь, но следующий трюк помог мне:

http://www.gamedev.net/blog/33/entry-2138456-seamless-noise/

Этот сотрудник использует функцию шума 4d и просто предоставляет значения xy двух окружностей в качестве значений xyzw для шума 4d. Результат зацикливается идеально.

Вот идея (упрощенная) для картинки 1000 * 1000:

for(i = 0;i < 1000; i++){

  for(j = 0; j < 1000; j++){

    nx = cos((i/1000) * 2 * PI);
    ny = cos((j/1000) * 2 * PI);
    nz = sin((i/1000) * 2 * PI);
    nw = sin((j/1000) * 2 * PI);

    looped_noise = noise_4D( nx, ny, nz, nw, octaves, persistence, lacunarity, blah...);
    noise_buffer[(i*1000)+j] = looped_noise;

  }
}
окр
источник
1

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

drxzcl
источник
0

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

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

Ничего
источник
0

На скриншоте я предполагаю, что генерируются только «большие» слои, поэтому шум кажется слишком регулярным и не хватает деталей.

Это может звучать глупо, но вы пытались увеличить переменную «detail» (строка 16)? В вашем коде он равен 1, что означает, что алгоритм будет генерировать только два слоя детализации перед остановкой. Попробуйте увеличить его примерно до 8.

Пользователь не найден
источник
0

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

Я работал над реализацией Simplex Noise для игры на C ++. Он поддерживает многооктавный шум 1D / 2D / 3D / 4D. Прямо сейчас единственная встроенная текстура - мрамор, но вы можете легко добавить больше:

(Http://code.google.com/p/battlestar-tux/source/browse/trunk/src/lib/procedural/)

i_grok
источник