Problem generowania terenu o kwadratach diamentów


11

Zaimplementowałem algorytm kwadratu diamentowego zgodnie z tym artykułem: http://www.lighthouse3d.com/opengl/terrain/index.php?mpd2

Problem polega na tym, że te strome klify dostaję na całej mapie. Zdarza się to na krawędziach, gdy teren jest rekurencyjnie podzielony:

wprowadź opis zdjęcia tutaj

Oto źródło:

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

}

Parametry: (x1, y1), (x2, y2) - współrzędne, które definiują region na mapie wysokości (domyślnie (0,0) (128 128). zasięg - w zasadzie maks. wysokość. (domyślnie 32)

Pomoc byłaby bardzo mile widziana.


Nie patrząc na kod, wygląda na to, że prawdopodobnie masz złe rogi w niewłaściwych wywołaniach w 4 wywołaniach rekurencyjnych na końcu. Mapa wygląda, jakby każdy kwadrat został obrócony / obrócony przed obliczeniem następnego zestawu, dzieląc mapę na dziwne klify. Dolna krawędź prawego górnego kwadratu wygląda tak, jakby pasowała do prawej krawędzi lewego górnego kwadratu i tak dalej.
— DampeS8N

Nie jestem pewny co masz na myśli. Środek układu współrzędnych znajduje się w lewym górnym rogu, oś x wskazuje w prawo, ay w dół. Tak więc w pierwszej iteracji (x1 = 0, y1 = 0), (x2 = 128, y2 = 128) i (x1 + hx = 64, y1 + hy = 64) jest środkiem kwadratu. Kwadrat jest zatem podzielony na 4 podkwarki: ((0,0) (64,64)), ((64,0) (128,64)), ((0,64) (64 128) i ((64, 64) (128 128). Wygląda mi dobrze ...
— kafka,

Odpowiedzi:


12

Na każdym poziomie podziału krok „kwadratowy” opiera się na wynikach „kroku diamentowego”. Ale ma to również wpływ na krok diamentu wytworzony w sąsiedniej komórce, którego nie rozliczasz. Przepisałbym funkcję DiamondSquare, aby iterować najpierw szerokość, a nie głębokość tak, jak ją obecnie masz.

Pierwszym problemem jest to, że ponieważ dwukrotnie obliczyłeś kwadratowe krawędzie, ignoruje on udział sąsiedniego punktu środkowego. Na przykład w artykule, do którego się odwołujesz,

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

ale twój kod działa skutecznie

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

tzn. dwukrotnie uwzględnia bieżący punkt środkowy, a nie sąsiedni punkt środkowy. Dlatego musisz przejść na szerokość, aby obliczyć poprzednie punkty środkowe.

Oto mój kod i wynik:.

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


Tak, myślałem również zgodnie z szerokim podejściem. Te fraktale zawsze powodują mi problemy. Podobnie było z hałasem Perlina i systemami L. Jesteś niesamowity.
— kafka

3

Jedną z możliwości jest to, że używasz skrótu do implementacji, którego nie robi algorytm na połączonej stronie.

W przypadku kwadratu obliczasz wysokość punktów za pomocą

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

którego algorytm strony wskazuje, że ma być używany podczas owijania mapy. Daje to wrażenie, że używasz wartości wysokości „następny kwadrat nad” do obliczenia tego. W najprostszym pierwszym przypadku punkt środkowy (o wysokości „e”) jest używany zarówno po lewej, jak i po prawej stronie do obliczenia f.

Jednak w algorytmie, do którego się odwołujesz, używasz rzeczywistych wartości innych kwadratów / diamentów, aby pomóc ci obliczyć wartość wysokości tego punktu kwadratowego. W ich algorytmie punkt drugiego poziomu jest obliczany według następującego wzoru:

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

Czy zauważysz brak duplikacji wartości?

Myślę, że powinieneś spróbować użyć nie zawijających się wersji podanych formuł. Myślę, że te będą się powtarzać lepiej.

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

Dzięki, to była pomocna obserwacja. Myślę, że nauczyłem się mojej zmiany, by nie przeskakiwać bezpośrednio do kodowania, kiedy widzę równania.
— kafka

Jesteś bardzo mile widziany. Sam też to robię dużo czasu ... „Słuchaj, coś, co mogę kodować. Muszę. Kodować. Teraz!”
— fnord
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.