Алгоритм зміщення середньої точки


14

MDPMDP

Це питання в основному вийшло з відчайдухи , витративши кілька годин на намагання з'ясувати проблему.

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

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

unsigned char** mdp(unsigned char** base, unsigned base_n, unsigned char r) {
    size_t n = (2 * base_n) - 1;

    unsigned char** map = new unsigned char*[n];
    for (unsigned i = 0; i < n; ++i) map[i] = new unsigned char[n];

    // Resize
    // 1 0 1
    // 0 0 0
    // 1 0 1
    for (size_t i = 0; i < n; i += 2) {
        for (size_t j = !(i % 2 == 0); j < n; j += 2) {
            map[i][j] = base[i / 2][j / 2];
        }
    }

    // Diamond algorithm
    // 0 0 0
    // 0 X 0
    // 0 0 0
    for (size_t i = 1; i < n; i += 2) {
        for (size_t j = 1; j < n; j += 2) {
            unsigned char& map_ij = map[i][j];

            unsigned char a = map[i - 1][j - 1];
            unsigned char b = map[i - 1][j + 1];
            unsigned char c = map[i + 1][j - 1];
            unsigned char d = map[i + 1][j + 1];
            map_ij = (a + b + c + d) / 4;

            unsigned char rv = std::rand() % r;
            if (map_ij + r < 255) map_ij += rv; // EDIT: <-- thanks! the bug! `map_ij + rv`, not `r`
            else map_ij = 255;
        }
    }

    // Square algorithm
    // 0 1 0
    // 1 0 1
    // 0 1 0
    for (size_t i = 0; i < n; ++i) {
        for (size_t j = (i % 2 == 0); j < n; j += 2) {
            unsigned char& map_ij = map[i][j];

            // get surrounding values
            unsigned char a = 0, b = a, c = a, d = a;
            if (i != 0) a = map[i - 1][j];
            if (j != 0) b = map[i][j - 1];
            if (j + 1 != n) c = map[i][j + 1];
            if (i + 1 != n) d = map[i + 1][j];

            // average calculation
            if (i == 0) map_ij = (b + c + d) / 3;
            else if (j == 0) map_ij = (a + c + d) / 3;
            else if (j + 1 == n) map_ij = (a + b + d) / 3;
            else if (i + 1 == n) map_ij = (a + b + c) / 3;
            else map_ij = (a + b + c + d) / 4;

            unsigned char rv = std::rand() % r;
            if (map_ij + r < 255) map_ij += rv;
            else map_ij = 255;
        }

    }

    return map;
}

Якщо у вас є які-небудь поради або ресурси, крім http://www.gameprogrammer.com/fractal.html та http://www.lighthouse3d.com/opengl/terrain/index.php?mpd2 для генерації місцевості на фрактальній основі, я б хотів оцінюйте їх також як коментарі.

Редагувати:

MDP

Це новий образ, згідно з пропозицією Фабіаса (ти), однак у ньому все ще є дивні химерності, які ви повинні мати можливість бачити відразу (маленькі «ямочки» скрізь).

Що може спричинити цю дивну поведінку? Оновлений вихідний код: http://www.pastie.org/1924223

Редагувати:

Велике спасибі Фабіану, що знайшов помилку перевірки меж, для тих, хто цікавиться, ось поточне рішення як 512x512 png. І поточний вихідний код (модифікований Fabian) . MDP

Редагувати (через роки): версія Python https://gist.github.com/dcousens/5573724#file-mdp-py


На знімках схоже, що кожна з крапок знаходиться на одній висоті. Чи однакові висоти кутів?
deft_code

1
Що варте того, ваші зображення виглядають дуже красиво. :)
ChrisE

scrand (): Я не зовсім впевнений, що я розумію - чи це повинно повертати підписаний символ на проміжку (-r / 2, r / 2]? Ямочки, як би мені не було, схожі на результат Суміжні області, здається, раптом знімають чорний колір, а потім піднімаються назад до білого. Загалом, це також виглядає так, що є різка смуга, знову підказуючи мені, що ви переповнюєтесь, можливо. більша точність (скажімо, ціле число), а потім затискання значень до діапазону [0,256] або [-128,127]?
ChrisE

Проблема була вирішена нижче, це було тому, що я перевіряв межі діапазону випадкового значення, а не його фактичного значення. Scrand () була тимчасовою функцією "шум", яка ідеально повертається [-128, 127]
уповільненийкавіар

Ах, круто! Радий почути, що зараз це працює.
ChrisE

Відповіді:


12

Алгоритм рекурсивно додає значення, але значення може бути позитивним або негативним (зазвичай + -1 / (2 ^ октава))

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

спробуйте починати з 127, а не нуля для чотирьох кутів, а також спробуйте підписаний знак char (тоді перевіряйте межі як верхнього, так і нижнього)

EDIT

тож ще дві речі потрібно змінити в основній (64 >> i), щоб отримати ефект половини в кожній октаві, а також вашу вихідну функцію (ту, що відображає остаточний [] [] tp imgdta [], ви просто потрібно поставити

imgdta [(i * n) + j] = 128 + остаточний [i] [j];

а не блок if if.

інша річ, я не впевнений, чому, але перевірка ваших меж не працює (це рядки 38 і 65), якщо ви видалите чек повністю, ви також помітите нові темні краплі, тож я думаю, вам може знадобитися просування до більшого типу Перш ніж робити межі, перевірте, чи хочете ви отримати більш галасливу картину, яку ви отримаєте з "64 / i".

ІНШИЙ РЕДАКТ

щойно вияснили, що це таке, ви порівнюєте проти 'r', а не 'rv', у перевірці меж. Ось фіксований код: http://pastie.org/1927076


Це, безумовно, був кращим способом вирішити це, але жодної сигари, як і раніше, схоже, у мого зображення все ще є деякі "химерності", я оновив початковий пост.
deceleratedcaviar

не впевнений, але рядок 93 виглядає неправильно, 64 / мені може знадобитися 64 >> я (як ви вдвічі менший за кожну октаву)
Річард Фабіан

А-а-а !! Дякую тобі, я не можу в це повірити, я знав, що це буде щось дурне для цієї другої проблеми. Полюбив ваш імпровізований код TGA, вибачте, я мав би вам врятувати неприємності і поставити заголовок.
deceleratedcaviar

3

Дві речі, які вискакують:

  1. Чи є у вас вагомі причини зробити це у фіксованій точці? З цим немає нічого поганого, і є безліч причин для його використання (особливо важливі вимоги до пам'яті, якщо ви плануєте рухатися до ВЕЛИЧЕЗНОЇ карти), але я б напевно почав із версії алгоритму з плаваючою комою. і перетворити його у фіксовану точку після того, як ви працюєте; це повинно, якщо нічого іншого, усунути одне правдоподібне джерело помилок (зокрема, я підозрюю, що ваше затискання може спричинити проблеми, а також умови, коли потрібно додати / субстратувати rv).
  2. Хоча з коду, який я бачу, важко зрозуміти, схоже, що ваш рандомізований зсув висоти масштабується з рівнем, і що в поєднанні з проблемою в (1) може викликати деякі проблеми - у вас не повинно бути витіснення на однакову суму на кожному рівні.

О, і одна неальгоритмічна річ: я настійно рекомендую не робити виділення у вашій функції mdp (); передайте два різних вже виділених масиви та зробіть ітерацію «на місці», переходячи від одного до іншого. Якщо нічого іншого, це дозволить вам робити пінг-понг вперед і назад, як ви робите шари, а не потрібно кожного разу виділяти новий масив.


Деякі хороші моменти, очевидно, що я просто намагаюся виправити алгоритм, реалізація далеко не ідеальна, я навіть не очищаю пам'ять на даний момент: P.
уповільненийкавіар

На цьому етапі масштабування пропусків дорівнює 64 / i, очевидно, я це зміню пізніше, але це насправді не пояснює діючий ефект ямочок. : S
уповільненийкавіар

0

Крім вищезазначеного, наразі ви не видаляєте пам'ять, яку ви виділяєте. Щоб виправити це, змініть рядок 104 з:

for (unsigned i = 1; i < 6; ++i) final = mdp(final, n, 64 / i);

до

for (unsigned i = 1; i < 6; ++i) {
  signed char** new_final = mdp(final, n, 64 / i);
  for (unsigned i = 0; i < n; ++i)
    delete[] final[i];
  delete[] final;
  final = new_final;
}

і додайте це після запису до файлу tga:

for (unsigned i = 0; i < n; ++i)
  delete[] final[i];
delete[] final;

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