Come posso creare un solido rumore piastrellabile per la generazione di mappe?


16

Ehi ragazzi, sto cercando di capire come generare frattali piastrellabili nel codice (per le mappe di gioco, ma questo è irrilevante ) Ho cercato di modificare il plug-in Solid Noise fornito con GIMP (con la mia comprensione estremamente limitata di come il codice funziona) ma non riesco a far funzionare correttamente il mio.

Il mio codice modificato finora (Java)

Modulo di rumore solido di GIMP che sto basando il mio codice su (C)

Ecco cosa sto cercando di ottenere ma questo è quello che sto ottenendo

Quindi, se qualcuno può vedere ciò che ho fatto di sbagliato, o ha un suggerimento su come potrei fare diversamente, lo apprezzerei molto. Grazie in anticipo. E se chiedo molto o solo un grosso fallimento nella vita, mi scuso.


provare a usare l' interpolazione bicubica anziché bilineare? Non ho idea se questo è il tuo problema, ma sembra che sia così.
Stephen Furlani,

Risposte:


4

Non seguo esattamente il tuo codice, ma ecco una descrizione semplificata dell'algoritmo che raggiungerà all'incirca l'effetto (basato sull'immagine che hai pubblicato).

La seguente spiegazione non è la versione super ottimizzata, ma concettualmente chiara (spero). Una volta che lo hai avviato, puoi ottimizzarlo (abbastanza drasticamente, in effetti).

  1. Genera n livelli di rumore casuale uniforme (solo pixel in scala di grigi casuali).
  2. Ora campiona ognuno di questi campionando ogni, 1, 2, 4, 8, ... 2 ^ (n-1) pixel e interpolando i pixel intermedi. Ogni strato è più liscio del precedente.
  3. Ora scala di questi con un fattore di 1, 2, 4, 8, ecc. Ogni strato è più scuro del precedente.
  4. Aggiungi tutti questi insieme.
  5. Normalizza dividendo ogni pixel con (1 + 2 + 4 + 8 + ... 2 ^ (n-1)).

Il passaggio difficile è il passaggio di campionamento e interpolazione. Supponiamo di essere nel livello saltando il campionamento ogni m-esimo pixel. Ecco l'idea di base per m> 1 (se m è 1, usiamo l'immagine così com'è):

for each pixel x and y
   left_sample_coord = m *(x / m) //(integer division, automatically truncated)
   right_sample_coord = (left_sample_point + m) % image_width
   top_sample_point = m*(y / m) 
   bottom_sample_coord = (top_sample_point + m) % image_height

   horizontal_weight = (x - left_sample_point) / (m - 1)
   vertical_weight = (y - top_sample_point) / (m - 1)

   sample_top_left = image(left_sample_coord, top_sample_point)
   //and the same for the other four corners

   //now combine the top two points
   top_interpolate = sample_top_left * horizontal_weight + sample_top_right * (1-horizontal_weight)

  //now combine the bottom two points
  bottom_interpolate = sample_bottom_left * horizontal_weight + sample_bottom_right * (1-horizontal_weight)

  //and combine these two last obtained values

  smooth_noise(x, y) = top_interpolate * vertical_weight  + bottom_interpolate * (1 - vertical_weight)

Alcuni consigli:

  • Il risultato dell'algoritmo sopra potrebbe sembrare un po 'sbiadito. È possibile ridurre questo effetto utilizzando lo stesso livello di rumore per tutti i livelli oppure migliorare il contrasto migliorando l'immagine in seguito.
  • L'algoritmo sopra utilizza l'interpolazione lineare, ma l'interpolazione del coseno (fare una ricerca) fornisce risultati molto migliori.
  • Rendi possibile guardare i tuoi livelli separatamente durante tutte le parti dell'algoritmo. Questo ti aiuterà a eliminare rapidamente i bug.

3

Sembra che il mio pastebin originale sia scaduto in qualche modo, quindi non ho modo di confrontare il mio codice non funzionante, ma nel mio gioco attuale ho attraversato e tradotto di nuovo il codice GIMP in Java e sembra funzionare bene ora.

Se qualcuno ha intenzione di utilizzare questo codice, consiglierei di modificare il costruttore per modificare i parametri di impostazione (dettagli e dimensioni) in modo da poter farlo funzionare come desideri. EDIT: mi sono reso conto che la mia domanda originale era di renderlo piastrellabile, quindi ricorda di impostare piastrellabile su true!

Codice: http://pastebin.com/KsfZ99Xa

Esempio: esempio di generatore perlin


2

Ho appena sfogliato le versioni Java e C e ho notato una leggera differenza nel modo in cui usi la funzione noise. Ecco il tuo:

int val = Math.abs((int) Math.floor(255.0 * noise(((double)col/(double)width), ((double)row/(double)height))));

Codice C:

val = (guchar) floor (255.0 * noise ((col - xoffset) / width,

                                           (row - yoffset) / height));

Perché hai scelto di non sottrarre l'offset? (col - xoffset) e (row - yoffset)

Mi sto solo chiedendo. Non ho tempo di fare un'analisi completa del codice.

Spero che sia di aiuto.


xoffset e yoffset sono calcolati nel modo in cui GIMP divide le immagini in griglie, ma il mio programma funziona su una sola tessera, quindi l'offset xey sarebbe 0
Nick Badal

2

Non so se potrebbe aiutare, ma il seguente trucco ha funzionato a meraviglia per me:

http://www.gamedev.net/blog/33/entry-2138456-seamless-noise/

Questo collega utilizza una funzione di rumore 4d e fornisce semplicemente i valori xy di due cerchi come valori xyzw per il rumore 4d. Il risultato è loop perfetto.

Ecco l'idea (semplificata) per un'immagine 1000 * 1000:

for(i = 0;i < 1000; i++){

  for(j = 0; j < 1000; j++){

    nx = cos((i/1000) * 2 * PI);
    ny = cos((j/1000) * 2 * PI);
    nz = sin((i/1000) * 2 * PI);
    nw = sin((j/1000) * 2 * PI);

    looped_noise = noise_4D( nx, ny, nz, nw, octaves, persistence, lacunarity, blah...);
    noise_buffer[(i*1000)+j] = looped_noise;

  }
}

1

Ti consiglio di usare l' algoritmo del diamante quadrato , noto anche come frattale al plasma o frattale casuale di spostamento del punto medio. Utilizzando questo algoritmo è molto semplice vincolare i bordi per avere gli stessi valori. Quando si genera un valore per un bordo, copiarlo sul bordo corrispondente sull'altro lato. Ciò produce una mappa di piastrellatura perfettamente.


0

C'è un ottimo articolo sulla generazione del rumore qui . Non è il rumore di Perlin come afferma l'articolo (in realtà è il rumore rosa), ma è ancora incredibilmente utile capire come vengono generate le immagini di rumore.

Quindi, per rispondere effettivamente alla tua domanda: per creare un'immagine di rumore piastrellabile, devi solo mantenere la "piastrellabilità" per tutta la generazione. Cioè, quando il rumore viene attenuato, lo si attenua come se si ripetesse all'infinito in tutte le direzioni - piastrellato.


0

Dallo screenshot, la mia ipotesi è che vengono generati solo i livelli "grandi", motivo per cui il rumore appare troppo regolare e privo di dettagli.

Può sembrare stupido, ma hai provato ad aumentare la variabile "dettaglio" (riga 16)? Nel tuo codice, è impostato su 1, il che significa che l'algoritmo genererà solo due livelli di dettaglio prima di arrestarsi. Prova ad aumentarlo a qualcosa come 8.


0

Dovresti anche dare un'occhiata a Simplex Noise , che è stato sviluppato da Ken Perlin per correggere alcuni dei difetti del rumore di Perlin.

Ho lavorato su un'implementazione di Simplex Noise per un gioco C ++. Supporta rumore 1D / 2D / 3D / 4D a ottava multipla. Al momento, l'unica trama incorporata è il marmo, ma potresti facilmente aggiungere altro:

(Http://code.google.com/p/battlestar-tux/source/browse/trunk/src/lib/procedural/)

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.