Проблема покоління алмазних квадратних ландшафтів


11

Я реалізував алгоритм алмазного квадрата відповідно до цієї статті: http://www.lighthouse3d.com/opengl/terrain/index.php?mpd2

Проблема полягає в тому, що я отримую ці круті скелі по всій карті. Це відбувається на узліссях, коли місцевість рекурсивно підрозділяється:

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

Ось джерело:

void DiamondSquare(unsigned x1,unsigned y1,unsigned x2,unsigned y2,float range)
    {      
    int c1 = (int)x2 - (int)x1;
    int c2 = (int)y2 - (int)y1;
    unsigned hx = (x2 - x1)/2;
    unsigned hy = (y2 - y1)/2;
    if((c1 <= 1) || (c2 <= 1))
            return;

// Diamond stage
float a = m_heightmap[x1][y1];
float b = m_heightmap[x2][y1];
float c = m_heightmap[x1][y2];
float d = m_heightmap[x2][y2];
float e = (a+b+c+d) / 4 + GetRnd() * range;

m_heightmap[x1 + hx][y1 + hy] = e;

// Square stage
float f = (a + c + e + e) / 4 + GetRnd() * range;
m_heightmap[x1][y1+hy] = f;
float g = (a + b + e + e) / 4 + GetRnd() * range;
m_heightmap[x1+hx][y1] = g;
float h = (b + d + e + e) / 4 + GetRnd() * range;
m_heightmap[x2][y1+hy] = h;
float i = (c + d + e + e) / 4 + GetRnd() * range;
m_heightmap[x1+hx][y2] = i;

DiamondSquare(x1, y1, x1+hx, y1+hy, range / 2.0);   // Upper left
DiamondSquare(x1+hx, y1, x2, y1+hy, range / 2.0);   // Upper right
DiamondSquare(x1, y1+hy, x1+hx, y2, range / 2.0);   // Lower left
DiamondSquare(x1+hx, y1+hy, x2, y2, range / 2.0);       // Lower right

}

Параметри: (x1, y1), (x2, y2) - координати, що визначають область на карті висоти (за замовчуванням (0,0) (128,128)). діапазон - в основному макс. висота. (за замовчуванням 32)

Допомога була б дуже вдячна.


Не дивлячись важко на свій код, схоже, що у 4-х рекурсивних дзвінків наприкінці, ймовірно, у вас неправильні кути неправильних дзвінків. Карта виглядає так, що кожен квадрат повертається / перевертається перед обчисленням наступного набору, таким чином, розділяючи карту на дивні скелі. Нижній край верхнього правого квадрата виглядає так, що він відповідає правому краю верхнього лівого квадрата тощо.
DampeS8N

Я не впевнений, що ти маєш на увазі. Центр системи координат знаходиться у верхньому лівому куті, вісь x вказує праворуч та y вниз. Тож у першій ітерації (x1 = 0, y1 = 0), (x2 = 128, y2 = 128) і (x1 + hx = 64, y1 + hy = 64) - центр квадрата. Таким чином, квадрат поділяється на 4 підквадри: ((0,0) (64,64)), ((64,0) (128,64)), ((0,64) (64,128)) і ((64, 64) (128,128)). Мені добре виглядає ...
kafka

Відповіді:


12

У кожному рівні підрозділу крок "квадрат" спирається на результати "алмазного кроку". Але це також є чинником алмазного кроку, виготовленого в сусідній клітині, на який ви не входите. Я б переписав функцію DiamondSquare для того, щоб повторити Ширину-першу, а не першу глибину, як у вас є.

Ваше перше питання полягає в тому, що оскільки ви двічі перераховуєте квадратні ребра, він ігнорує внесок сусідньої центральної точки. Наприклад, у статті, на яку ви посилаєтесь,

P = (J + G + K + E)/4 + RAND(d)

але ваш код ефективно робить

P = (J + G + J + E)/4 + RAND(d)

тобто він чинник у поточній центральній точці вдвічі, а не сусідній центральній точці. Ось чому вам потрібно пройти в ширину першим, щоб у вас були підраховані попередні центральні точки.

Ось мій код і вихід:.

void DiamondSquare(unsigned x1, unsigned y1, unsigned x2, unsigned y2, float range, unsigned level) {
    if (level < 1) return;

    // diamonds
    for (unsigned i = x1 + level; i < x2; i += level)
        for (unsigned j = y1 + level; j < y2; j += level) {
            float a = m_heightmap[i - level][j - level];
            float b = m_heightmap[i][j - level];
            float c = m_heightmap[i - level][j];
            float d = m_heightmap[i][j];
            float e = m_heightmap[i - level / 2][j - level / 2] = (a + b + c + d) / 4 + GetRnd() * range;
        }

    // squares
    for (unsigned i = x1 + 2 * level; i < x2; i += level)
        for (unsigned j = y1 + 2 * level; j < y2; j += level) {
            float a = m_heightmap[i - level][j - level];
            float b = m_heightmap[i][j - level];
            float c = m_heightmap[i - level][j];
            float d = m_heightmap[i][j];
            float e = m_heightmap[i - level / 2][j - level / 2];

            float f = m_heightmap[i - level][j - level / 2] = (a + c + e + m_heightmap[i - 3 * level / 2][j - level / 2]) / 4 + GetRnd() * range;
            float g = m_heightmap[i - level / 2][j - level] = (a + b + e + m_heightmap[i - level / 2][j - 3 * level / 2]) / 4 + GetRnd() * range;
        }

    DiamondSquare(x1, y1, x2, y2, range / 2, level / 2);
}

http://i.imgur.com/laBhN.png


Так, я також міркував за принципом широкого підходу. Ці фрактали завжди викликають у мене проблеми. Те саме було і з шумом Perlin та L-системами. Ти неймовірний.
кафка

3

Однією з можливостей є те, що ви використовуєте ярлик зі своєю реалізацією, що алгоритм на вашій пов’язаній сторінці не має.

Для квадратного етапу ви обчислюєте висоту точок за допомогою

float f = (a + c + e + e) / 4 + GetRnd() * range;
m_heightmap[x1][y1+hy] = f;

який алгоритм сторінки вказує використовувати, якщо ви загортаєте свою карту. Це дає вигляд, що ви використовуєте значення висоти "наступний квадрат над" для обчислення цього. У найпростішому, першому випадку, центральна точка (з висотою 'e') використовується для лівої та правої сторін для обчислення f.

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

N = (K + A + J + F)/4 + RAND(d)

Помічаєте відсутність дублювання значення там?

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

F = (A + C + E)/3 + ...
    instead of
F = (A + C + E + E)/4 + ...

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

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