Problema di generazione del terreno a diamante quadrato


11

Ho implementato un algoritmo a diamante quadrato secondo questo articolo: http://www.lighthouse3d.com/opengl/terrain/index.php?mpd2

Il problema è che ho queste ripide scogliere su tutta la mappa. Succede ai bordi, quando il terreno è suddiviso ricorsivamente:

inserisci qui la descrizione dell'immagine

Ecco la fonte:

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

}

Parametri: (x1, y1), (x2, y2) - coordinate che definiscono una regione su una heightmap (default (0,0) (128.128)). gamma - sostanzialmente max. altezza. (impostazione predefinita 32)

L'aiuto sarebbe molto apprezzato.


Senza guardare attentamente al tuo codice, sembra che tu abbia probabilmente gli angoli sbagliati nelle chiamate sbagliate nelle 4 chiamate ricorsive alla fine. La mappa sembra che ogni quadrato sia ruotato / capovolto prima di calcolare il set successivo, quindi suddividendo la mappa su strane scogliere. Il bordo inferiore del quadrato in alto a destra sembra corrispondere al bordo destro del quadrato in alto a sinistra, e così via.
DampeS8N,

Non sono sicuro di cosa intendi. Il centro del sistema di coordinate si trova nell'angolo in alto a sinistra, l'asse x punta a destra e y in basso. Quindi nella prima iterazione (x1 = 0, y1 = 0), (x2 = 128, y2 = 128) e (x1 + hx = 64, y1 + hy = 64) è il centro del quadrato. Il quadrato è quindi diviso in 4 sottosquadre: ((0,0) (64,64)), ((64,0) (128,64)), ((0,64) (64.128)) e ((64, 64) (128.128)). Mi sembra perfetto ...
Kafka,

Risposte:


12

In ogni livello di suddivisione, il passo "quadrato" si basa sui risultati del "passo di diamante". Ma influenza anche il passo del diamante prodotto nella cella adiacente, che non si sta prendendo in considerazione. Riscriverei la funzione DiamondSquare per iterare Breadth-first, invece di depth-first come lo hai attualmente.

Il tuo primo problema è che dal momento che ricalcoli due volte i bordi quadrati, ignora il contributo del punto centrale adiacente. Ad esempio, nell'articolo a cui fai riferimento,

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

ma il tuo codice lo fa efficacemente

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

cioè tiene conto della corrente tiene conto del punto centrale due volte, non del punto centrale adiacente. Questo è il motivo per cui è necessario andare prima di tutto, in modo da avere i punti centrali precedenti calcolati.

Ecco il mio codice e l'output:.

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


Sì, stavo anche pensando secondo le linee del primo approccio. Questi frattali mi causano sempre problemi. Era lo stesso con il rumore Perlin e i sistemi a L. Sei fantastico.
kafka,

3

Una possibilità è che stai implementando un collegamento con l'implementazione che l'algoritmo nella tua pagina collegata non ha.

Per la fase quadrata, stai calcolando l'altezza dei punti con

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

che l'algoritmo della pagina indica da usare se stai avvolgendo la tua mappa. Ciò dà l'impressione che si stia utilizzando il valore di altezza del "riquadro successivo" per calcolare questo valore. Nel primo caso più semplice, il punto centrale (con altezza 'e') viene utilizzato su entrambi i lati sinistro e destro per calcolare f.

Tuttavia, l'algoritmo a cui fai riferimento utilizza i valori effettivi degli altri quadrati / diamanti per aiutarti a calcolare il valore dell'altezza di questo punto quadrato. Nel loro algoritmo, il punto di secondo livello viene calcolato con la seguente formula:

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

Notare la mancanza di duplicazione di un valore lì dentro?

Penso che potresti voler provare a usare le versioni non-wrapping delle formule fornite, quelle che ricorderanno meglio, penso.

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

Grazie, è stata un'osservazione utile. Penso di aver imparato la mia lesione a non passare direttamente alla codifica, quando vedo le equazioni.
kafka,

Sei il benvenuto. Lo faccio anch'io un sacco di tempo ... "Guarda, qualcosa che posso codificare. Deve. Codificare. Adesso!"
fnord,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.