Як створити твердий плівковий шум для створення карти?


16

Ей, хлопці, я намагаюся зрозуміти, як генерувати фрактали в коді (для карт ігор, але це не має значення ) код працює), але я не можу заставити мою працювати правильно.

Мій модифікований код поки що (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

Схоже, мій оригінальний пастин якось закінчився, тому я не маю можливості порівнювати свій неробочий код, але в моїй поточній грі я знову пройшов і перевів GIMP-код у Java, і зараз, здається, він працює добре.

Якщо хтось планує використовувати цей код, я рекомендую змінити конструктор, щоб змінити параметри налаштування (деталі та розмір), щоб ви могли змусити його працювати, як хочете. EDIT: Я зрозумів, що моє первісне запитання стосується того, щоб зробити його плитковим, тому пам’ятайте, що встановити доступне для істини!

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

Приклад: Приклад генератора перлін


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) та (рядок - yoffset)

Просто цікаво. У мене немає часу зробити повний аналіз коду.

Сподіваюсь, це допомагає.


xoffset і yoffset повинні обчислювати так, як GIMP ділить зображення на сітки, але моя програма працює на одній плитці, так що зміщення x і y буде 0
Nick Badal

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

Я рекомендую використовувати алгоритм алмазного квадрата , також відомий як фрактал плазми або фрактал середнього зсуву середньої точки. За допомогою цього алгоритму дуже легко обмежити краї, щоб вони мали однакові значення. Коли ви генеруєте значення для краю, скопіюйте його до відповідного краю з іншого боку. Це дає ідеально плиткову карту.


0

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

Отже, щоб насправді відповісти на ваше запитання: щоб створити зображення шумоподібної плитки, вам просто потрібно зберегти "плиткоздатність" протягом усього покоління. Тобто, коли шум згладжується, ви згладжуєте його так, ніби він повторюється нескінченно у всіх напрямках - плиткою.


0

Зі скріншоту я здогадуюсь, що генеруються лише "великі" шари, саме тому шум видається занадто регулярним і не вистачає деталей.

Це може здатися дурним, але ви намагалися збільшити змінну "деталей" (рядок 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/)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.