Perché il mio rumore Perlin sembra "bloccato"?


21

Ho provato a implementare il Perlin Noise da solo usando solo la teoria (seguendo flafla2.github.io/2014/08/09/perlinnoise.html). Sfortunatamente non sono stato in grado di ottenere l'aspetto del rumore "originale" Perlin.

Qual è la ragione per cui il codice seguente mostra una versione a blocchi di Perlin Noise?

Cosa dovrei migliorare / modificare nel codice in modo da renderlo Perlin Noise senza gli artefatti?

Sospetto che potrebbero esserci problemi nel modo in cui interpolo o nel gradsvettore. Il gradsvettore contiene prodotti punto di (vettore casuale per punto reticolare) e (vettore dimensione) - per tutti e 4 i punti reticolo vicini. (I vettori casuali e di dimensione sono descritti nel primo collegamento.)

GLSL Sandbox: http://glslsandbox.com/e#32663.0

Manufatti nel rumore

float fade(float t) { return t * t * t * (t * (t * 6. - 15.) + 10.); }
vec2 smooth(vec2 x) { return vec2(fade(x.x), fade(x.y)); }

vec2 hash(vec2 co) {
    return fract (vec2(.5654654, -.65465) * dot (vec2(.654, 57.4), co));
}

float perlinNoise(vec2 uv) {
    vec2 PT  = floor(uv);
    vec2 pt  = fract(uv);
    vec2 mmpt= smooth(pt);

    vec4 grads = vec4(
        dot(hash(PT + vec2(.0, 1.)), pt-vec2(.0, 1.)),   dot(hash(PT + vec2(1., 1.)), pt-vec2(1., 1.)),
        dot(hash(PT + vec2(.0, .0)), pt-vec2(.0, .0)),   dot(hash(PT + vec2(1., .0)), pt-vec2(1., 0.))
    );

    return 5.*mix (mix (grads.z, grads.w, mmpt.x), mix (grads.x, grads.y, mmpt.x), mmpt.y);
}

float fbm(vec2 uv) {
    float finalNoise = 0.;
    finalNoise += .50000*perlinNoise(2.*uv);
    finalNoise += .25000*perlinNoise(4.*uv);
    finalNoise += .12500*perlinNoise(8.*uv);
    finalNoise += .06250*perlinNoise(16.*uv);
    finalNoise += .03125*perlinNoise(32.*uv);

    return finalNoise;
}

void main() {
    vec2 position = gl_FragCoord.xy / resolution.y;
    gl_FragColor = vec4( vec3( fbm(3.*position) ), 1.0 );
}

Risposte:


24

L'interpolazione sembra a posto. Il problema principale qui è che la funzione hash che stai usando non è molto buona. Se guardo solo un'ottava e visualizzo il risultato hash emettendo hash(PT).x, ottengo qualcosa del genere:

cattiva funzione hash

Questo dovrebbe essere completamente casuale per quadrato della griglia, ma puoi vedere che ha molti schemi di linea diagonale (sembra quasi una scacchiera), quindi non è un hash molto casuale e questi schemi verranno visualizzati in il rumore prodotto da esso.

L'altro problema è che il tuo hash restituisce solo vettori di gradiente in [0, 1], mentre dovrebbero essere in [−1, 1] per ottenere gradienti in tutte le direzioni. Quella parte è facile da correggere rimappando.

Per risolvere questi problemi, ho cambiato il codice per utilizzare questa funzione hash (che ho imparato da Mikkel Gjoel, e probabilmente è dovuta a un articolo di WJJ Rey ):

vec2 hash(vec2 co) {
    float m = dot(co, vec2(12.9898, 78.233));
    return fract(vec2(sin(m),cos(m))* 43758.5453) * 2. - 1.;
}

Tieni presente che a causa delle funzioni di attivazione sarà un po 'più costoso della tua versione. Tuttavia, migliora considerevolmente l'aspetto del rumore risultante:

rumore fbm con migliore funzione hash


Grazie molto molto per la spiegazione. Questo è forse fuori tema, ma lo chiederò comunque; in alcuni codici sorgente che calcolano il rumore, le persone usano il vettore vec3 (1, 57, 113) per calcolare il prodotto punto con le coordinate correnti (suppongo che l'obiettivo sia anche quello di ottenere un hash). Perché questa particolare scelta di costanti (57 è circa 1 radiante in gradi, 133 = circa 2 * radiante in gradi)? È a causa della periodicità nelle funzioni di attivazione? Non riesco a cercarlo su Google.
Sarasvati,

3
@sarasvati Non ne sono proprio sicuro, ma suppongo che 57 e 113 siano scelti perché sono numeri primi. (113 è primo; 57 non lo è, ma è 3 * 19, quindi è ancora piuttosto primordiale ... se questa è una cosa.) Moltiplicare o modificare un numero primo iso tende a confondere i bit, quindi non è raro ingrediente negli hash.
Nathan Reed,

1
@cat Dubito che GLSL abbia un PRNG, dato che i programmi GLSL sono deterministici.
user253751,

1
Sembra che ci siano diverse potenziali nuove domande in questo thread di commenti ...
trichoplax,

1
Stavo avendo quegli artefatti e questa funzione rand () l'ha risolto. Il problema è dopo che ho camminato come 2 km nel mio terreno, manufatti come gli OP hanno ripreso a comparire. Stava usando la funzione hash qui: amindforeverprogramming.blogspot.com/2013/07/… che ha causato la scomparsa degli artefatti (tranne che per distanze di 100 km, bc di imprecisione, ma va bene ho dovuto dividere in blocchi e ho ottenuto lavorare con l'hash di entrambi i valori, il che farà funzionare il rumore del perlin quasi indefinitamente). Quindi, lascerò questo qui forse per aiutare chiunque abbia lo stesso problema.
Nicholas Pipitone,
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.