Algoritmo di spostamento del punto medio


14

MDPMDP

Questa domanda è emersa principalmente per pura disperazione , dopo aver trascorso diverse ore a cercare di capire il problema.

Se guardi all'immagine sopra, dovresti vedere che il mio algoritmo di algoritmo di spostamento del punto medio funziona (in qualche modo) con successo; nel produrre un modello di rumore in qualche modo coerente.

Tuttavia, sta lasciando una griglia tratteggiata nera sull'immagine e non ho idea del perché. Posso prevedere che questo sia un problema in matematica, ma non riesco proprio a vederlo; né questo è stato indicato in alcuna risorsa online come possibile problema; così ogni aiuto sarà apprezzato per dare la caccia a questo bug.

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;
}

Se hai suggerimenti o risorse diversi da http://www.gameprogrammer.com/fractal.html e http://www.lighthouse3d.com/opengl/terrain/index.php?mpd2 per la generazione di terreni basati su frattali, vorrei apprezzali anche come commenti.

Modificare:

MDP

Questa è la nuova immagine, come suggerito da Fabians (ty), tuttavia ha ancora alcune strane stranezze, che dovresti essere in grado di vedere immediatamente (piccole 'fossette' ovunque).

Cosa potrebbe causare questo strano comportamento? Codice sorgente aggiornato: http://www.pastie.org/1924223

Modificare:

Mille grazie a Fabian nel trovare l'errore di controllo dei limiti, per chi fosse interessato, ecco la soluzione attuale come 512x512 png. E l' attuale codice sorgente (modificato da Fabian) . MDP

Modifica (anni dopo): versione di Python https://gist.github.com/dcousens/5573724#file-mdp-py


Nelle immagini, sembra che ciascuno dei punti sia alla stessa altezza. Anche gli angoli sono alla stessa altezza?
deft_code

1
Per quello che vale, le tue immagini sembrano molto belle. :)
ChrisE,

scrand (): Non sono del tutto sicuro di aver capito - questo dovrebbe restituire un carattere con segno sull'intervallo (-r / 2, r / 2]? Le fossette, a me comunque, sembrano un po 'come il risultato di troppo pieno. Le aree adiacenti sembrano improvvisamente diventare nere, per poi risalire di nuovo in bianco. Nel complesso, sembra anche che ci sia una banda acuminata, suggerendo ancora una volta che stai traboccando, forse. Ti dispiacerebbe fare la matematica in un maggiore precisione (diciamo, intero), e quindi bloccare i valori nell'intervallo [0,256] o [-128,127]?
ChrisE

Il problema è stato risolto di seguito, era perché stavo controllando i limiti rispetto all'intervallo del valore casuale, non al suo valore reale. Lo scrand () era una funzione temporanea di "rumore" che ritorna idealmente [-128, 127]
deceleratedcaviar

Ah, bello! Sono contento di sentire che ora funziona.
ChrisE,

Risposte:


12

L'algoritmo aggiunge ricorsivamente un valore, ma il valore può essere positivo o negativo (normalmente + -1 / (2 ^ ottava))

Se inizi da zero e aggiungi solo valori positivi, puoi solo salire, ed è per questo che stai vedendo i vertici abbassati.

prova a partire da 127 anziché zero per i quattro angoli, e prova anche il carattere con segno (quindi controlla i tuoi limiti sia in alto che in basso)

MODIFICARE

quindi, altre due cose devono cambiare nel main (64 >> i) per ottenere il mezzo effetto ad ogni ottava, e anche la tua funzione di output (quella che mappa l'ultimo [] [] tp imgdta [], devi solo bisogno di inserire

imgdta [(i * n) + j] = 128 + final [i] [j];

piuttosto che il blocco if else.

un'altra cosa, non sono sicuro del perché, ma il controllo dei limiti non riesce (ovvero le righe 38 e 65) se si rimuove totalmente il controllo, si notano anche alcune nuove macchie scure, quindi penso che potrebbe essere necessario passare a un tipo più grande prima di fare i limiti controlla se vuoi l'immagine più rumorosa che ottieni con "64 / i".

UN ALTRO EDIT

ho appena scoperto di cosa si trattava, confrontando 'r', non 'rv', nel controllo dei limiti. Ecco il codice fisso: http://pastie.org/1927076


Questo è stato sicuramente il modo migliore per farlo, ma al momento nessun sigaro sembra che la mia immagine abbia ancora delle "stranezze", ho aggiornato il post originale.
deceleratedcaviar

non sono sicuro ma la riga 93 sembra sbagliata, 64 / i potrebbe essere necessario 64 >> i (dato che metà dell'effetto ogni ottava)
Richard Fabian,

Ahhh !! Grazie mille, non ci posso credere, sapevo che sarebbe stato qualcosa di stupido per quel secondo problema. Mi è piaciuto molto il tuo codice TGA improvvisato, mi dispiace, avrei dovuto salvarti il ​​problema e mettere l'intestazione.
deceleratedcaviar

3

Due cose che saltano fuori:

  1. Hai un motivo convincente per farlo in virgola fissa? Di per sé non c'è nulla di sbagliato, e ci sono molte ragioni per usarlo (in particolare i requisiti di memoria se stai pensando di salire su una mappa ENORME), ma sicuramente inizierei con una versione in virgola mobile dell'algoritmo e convertilo in virgola fissa dopo averlo fatto funzionare; ciò dovrebbe, se non altro, eliminare una fonte plausibile di errori (in particolare, sospetto che il tuo bloccaggio possa causare problemi e le condizioni per quando aggiungere / sottrarre camper).
  2. Sebbene sia difficile distinguerlo dal codice che vedo, non sembra che il tuo spostamento in altezza randomizzato si ridimensioni con il livello e che combinato con il problema in (1) possa causare alcuni dei problemi - non dovresti esserlo spostando lo stesso importo ad ogni livello.

Oh, e una cosa non algoritmica: consiglio vivamente di non fare allocazioni nella funzione mdp (); passare in due diverse matrici già allocate ed eseguire l'iterazione "sul posto", passando dall'una all'altra. Se non altro, questo ti consentirà di eseguire il ping-pong avanti e indietro mentre esegui i livelli anziché dover allocare un nuovo array ogni volta.


Alcuni punti positivi, ovviamente sto solo cercando di ottenere l'algoritmo corretto, l'implementazione è tutt'altro che ideale, a questo punto non pulisco nemmeno la memoria: P.
deceleratedcaviar

A questo punto, il ridimensionamento dei passaggi è 64 / i, ovviamente lo cambierò in seguito, ma non spiega davvero l'effetto fossette attualmente sperimentato. : S
deceleratedcaviar

0

Oltre a quanto sopra, al momento non stai eliminando la memoria che stai allocando. Per rimediare a ciò, cambia la riga 104 da:

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

per

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;
}

e aggiungilo dopo averlo scritto nel file tga:

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

Sono molto consapevole di come ripulire la memoria, ma dato che si trattava solo di un prototipo di algoritmo e che sarebbe stato riscritto per utilizzare i vettori, volevo solo assicurarmi che fosse corretto.
deceleratedcaviar
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.