Funkcje losowe / szum dla GLSL

179

Ponieważ producenci sterowników GPU zwykle nie zadają sobie trudu, aby wdrożyć je noiseXw GLSL, szukam zestawu funkcji narzędziowych „szwajcarski scyzoryk do randomizacji grafiki” , najlepiej zoptymalizowanego do użycia w modułach cieniujących GPU. Wolę GLSL, ale kod zrobi dla mnie jakikolwiek język, nie mam nic przeciwko tłumaczeniu go na GLSL.

W szczególności oczekiwałbym:

a) Funkcje pseudolosowe - N-wymiarowy, równomierny rozkład na [-1,1] lub powyżej [0,1], obliczony na podstawie nasion M-wymiarowych (najlepiej dowolna wartość, ale nie mam nic przeciwko ograniczeniu nasion na przykład 0..1 dla jednolitego rozkładu wyników). Coś jak:

float random  (T seed);
vec2  random2 (T seed);
vec3  random3 (T seed);
vec4  random4 (T seed);
// T being either float, vec2, vec3, vec4 - ideally.

b) Ciągły hałas, taki jak szum Perlina - znowu, wymiar N, + - równomierny rozkład, z ograniczonym zestawem wartości i, dobrze wyglądający (niektóre opcje konfiguracji wyglądu, takie jak poziomy Perlina, mogą być również przydatne). Spodziewałbym się takich podpisów:

float noise  (T coord, TT seed);
vec2  noise2 (T coord, TT seed);
// ...

Nie przepadam za teorią generowania liczb losowych, więc najchętniej wybrałbym gotowe rozwiązanie , ale doceniłbym również odpowiedzi typu „oto bardzo dobry, wydajny 1D rand (), i pozwól mi wyjaśnić jak zrobić dobry N-wymiarowy rand () na wierzchu ... " .

Kos
źródło

Odpowiedzi:

263

Do bardzo prostych pseudolosowych rzeczy używam tego onelinera, który znalazłem gdzieś w Internecie:

float rand(vec2 co){
    return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}

Możesz również wygenerować teksturę szumu za pomocą dowolnego PRNG, który ci się podoba, a następnie załaduj go w normalny sposób i wypróbuj wartości w module cieniującym; Mogę wykopać próbkę kodu później, jeśli chcesz.

Sprawdź także ten plik dla implementacji GLSL hałasu Perlin i Simplex autorstwa Stefana Gustavsona.

appas
źródło
14
Jak używać vec2 co? czy to jest zasięg? nasionko?
Ross
12
Strzeż niskiej precyzji zmiennoprzecinkowych shaderów fragmentów z tego algorytmu (np S3 ARM Mali): stackoverflow.com/questions/11293628/... . Projekt github.com/ashima/webgl-noise nie wydaje się mieć problemów z niskim poziomem.
PT
4
FWIW, opisana tutaj funkcja jest omówiona bardziej szczegółowo tutaj .
Loomchild
3
FYI: Rozkład tej funkcji jest okropny.
Tara,
3
Jestem nowicjuszem w GLSL, czy ktoś może wyjaśnić, dlaczego co.xyjest używany zamiast co?
kelin
83

Przyszło mi do głowy, że można użyć prostej funkcji skrótu do liczb całkowitych i wstawić wynik do mantysy pływaka. IIRC specyfikacja GLSL gwarantuje 32-bitowe liczby całkowite bez znaku i reprezentację zmiennoprzecinkową IEEE binary32, więc powinna być idealnie przenośna.

Właśnie tego spróbowałem. Wyniki są bardzo dobre: ​​z każdym próbowanym wejściem wygląda dokładnie jak statyczny, bez widocznych wzorów. W przeciwieństwie do popularnego fragmentu sin / fract ma dość wyraźne ukośne linie na moim GPU przy tych samych danych wejściowych.

Wadą jest to, że wymaga GLSL v3.30. I choć wydaje się dość szybki, nie oceniłem empirycznie jego wydajności. AMD Shader Analyzer twierdzi, że 13,33 pikseli na zegar dla wersji vec2 na HD5870. Kontrast z 16 pikselami na zegar dla fragmentu sin / fract. Jest to z pewnością trochę wolniejsze.

Oto moja implementacja. Zostawiłem to w różnych kombinacjach tego pomysłu, aby ułatwić czerpanie własnych funkcji.

/*
    static.frag
    by Spatial
    05 July 2013
*/

#version 330 core

uniform float time;
out vec4 fragment;



// A single iteration of Bob Jenkins' One-At-A-Time hashing algorithm.
uint hash( uint x ) {
    x += ( x << 10u );
    x ^= ( x >>  6u );
    x += ( x <<  3u );
    x ^= ( x >> 11u );
    x += ( x << 15u );
    return x;
}



// Compound versions of the hashing algorithm I whipped together.
uint hash( uvec2 v ) { return hash( v.x ^ hash(v.y)                         ); }
uint hash( uvec3 v ) { return hash( v.x ^ hash(v.y) ^ hash(v.z)             ); }
uint hash( uvec4 v ) { return hash( v.x ^ hash(v.y) ^ hash(v.z) ^ hash(v.w) ); }



// Construct a float with half-open range [0:1] using low 23 bits.
// All zeroes yields 0.0, all ones yields the next smallest representable value below 1.0.
float floatConstruct( uint m ) {
    const uint ieeeMantissa = 0x007FFFFFu; // binary32 mantissa bitmask
    const uint ieeeOne      = 0x3F800000u; // 1.0 in IEEE binary32

    m &= ieeeMantissa;                     // Keep only mantissa bits (fractional part)
    m |= ieeeOne;                          // Add fractional part to 1.0

    float  f = uintBitsToFloat( m );       // Range [1:2]
    return f - 1.0;                        // Range [0:1]
}



// Pseudo-random value in half-open range [0:1].
float random( float x ) { return floatConstruct(hash(floatBitsToUint(x))); }
float random( vec2  v ) { return floatConstruct(hash(floatBitsToUint(v))); }
float random( vec3  v ) { return floatConstruct(hash(floatBitsToUint(v))); }
float random( vec4  v ) { return floatConstruct(hash(floatBitsToUint(v))); }





void main()
{
    vec3  inputs = vec3( gl_FragCoord.xy, time ); // Spatial and temporal inputs
    float rand   = random( inputs );              // Random per-pixel value
    vec3  luma   = vec3( rand );                  // Expand to RGB

    fragment = vec4( luma, 1.0 );
}

Zrzut ekranu:

Wyjście losowe (vec3) w static.frag

Sprawdziłem zrzut ekranu w programie do edycji obrazów. Istnieje 256 kolorów, a średnia wartość to 127, co oznacza, że ​​rozkład jest jednolity i obejmuje oczekiwany zakres.

Przestrzenny
źródło
17
+1 za dobry pomysł i wdrożenie. Poddałbym w wątpliwość twierdzenie, że ponieważ jest 256 kolorów, a średnia wartość wynosi 127, rozkład musi być jednolity (w ścisłym tego słowa znaczeniu). Może być jednolity, ale nie sądzę, żebyśmy o tym jeszcze wiedzieli. Na przykład rozkład krzywej dzwonowej może mieć tę samą średnią i liczbę kolorów, ale nie byłby jednolity.
LarsH
Zagłosowałem to z powodu podanego przez @LarsH.
Autumnsault
Cóż, jest wystarczająco dobry dla większości aplikacji, które nie wymagają jednolitości. :-)
itmuckel
5
Z mojego punktu widzenia histogram wydaje się bardzo jednolity ... Powiedziałbym, że jest wystarczająco dobry dla większości aplikacji, które również wymagają jednolitości. (Jedynymi wartościami, które wydają się być generowane mniej niż inne, są 0 i 255)
leviathanbadger
Dzięki. Moje prawdopodobieństwo jest zardzewiałe. Po zapoznaniu się z zestawem instrukcji GCN powinno to być bardzo szybkie na nowszym sprzęcie, ponieważ bezpośrednio obsługują operacje na polu bitowym w swoich zestawach instrukcji. Testy, które wykonałem na starszym sprzęcie.
Przestrzenny
73

Implementacja Gustavsona wykorzystuje teksturę 1D

Nie, nie robi tego, nie od 2005 roku. Po prostu ludzie nalegają na pobranie starej wersji. Wersja podana w podanym linku używa tylko 8-bitowych tekstur 2D.

Nowa wersja autorstwa Iana McEwana z Ashimy i mnie nie używa tekstury, ale działa z około połową prędkości na typowych platformach stacjonarnych z dużą przepustowością tekstur. Na platformach mobilnych wersja bez tekstur może być szybsza, ponieważ teksturowanie jest często istotnym wąskim gardłem.

Nasze aktywnie utrzymywane repozytorium źródeł to:

https://github.com/ashima/webgl-noise

Tutaj znajduje się zbiór wersji hałasu bez tekstur i tekstur wykorzystujących teksturę (przy użyciu tylko tekstur 2D):

http://www.itn.liu.se/~stegu/simplexnoise/GLSL-noise-vs-noise.zip

Jeśli masz jakieś konkretne pytania, wyślij mi e-mail bezpośrednio (mój adres e-mail można znaleźć w classicnoise*.glslźródłach).

Stefan Gustavson
źródło
4
Tak, implementacja, o której mówię, twój kod na davidcornette.com, do którego link @dep, używa tekstury 1D: glBindTexture(GL_TEXTURE_1D, *texID);itp. Nie jest jasne, co rozumiesz przez „ podany przez ciebie link”, ponieważ cytujesz z mojej odpowiedzi ale ta odpowiedź nie zawierała linku do Twojej implementacji. Zaktualizuję moją odpowiedź, aby wyjaśnić, o czym mówię, i odzwierciedlić nowe informacje, które podałeś. Charakteryzowanie ludzi jako „nalegających” na pobranie starej wersji jest zniekształceniem, którego nie przypisujesz.
LarsH,
1
PS Możesz napisać do Davida Cornette'a (on ma dane kontaktowe na davidcornette.com ) i poprosić go o zmianę swojego linku na davidcornette.com/glsl/links.html, aby link do twojego repozytorium źródłowego. Wyślę mu również e-maila.
LarsH,
1
PPS Czy możesz wyjaśnić, która wersja używa tylko 8-bitowych tekstur 2D? Wygląda na to, że może to być dobra opcja dla niektórych platform ...
LarsH,
31

Złoty hałas

// Gold Noise ©2015 [email protected]
// - based on the Golden Ratio
// - uniform normalized distribution
// - fastest static noise generator function (also runs at low precision)

float PHI = 1.61803398874989484820459;  // Φ = Golden Ratio   

float gold_noise(in vec2 xy, in float seed){
       return fract(tan(distance(xy*PHI, xy)*seed)*xy.x);
}

Zobacz teraz Złoty szum w swojej przeglądarce!

wprowadź opis zdjęcia tutaj

Ta funkcja poprawiła rozkład losowy w stosunku do bieżącej funkcji w odpowiedzi @appas z dnia 9 września 2017 r .:

wprowadź opis zdjęcia tutaj

Funkcja @appas jest również niekompletna, ponieważ nie ma dostarczanego materiału siewnego (UV nie jest materiałem siewnym - taki sam dla każdej ramki) i nie działa z chipsetami o niskiej precyzji. Złoty szum działa domyślnie z małą precyzją (znacznie szybciej).

Dominic Cerisano
źródło
Dzięki za opublikowanie tego. Czy rozważysz opublikowanie wersji do uruchomienia, np. Na shadertoy.com, aby ludzie mogli wypróbować ją w przeglądarce?
LarsH
@snb Shadertoy.com przechodzi konserwację w tym miesiącu, zachowaj cierpliwość. Również jasno udokumentowałem wymaganie dotyczące irracjonalnych wartości nasion w kodzie tam zawartym. Ponieważ szum złota zwraca skalar, konstruowanie w nim wektorów jest banalne, a także udokumentowane w kodzie.
Dominic Cerisano,
7
Nie sądzę, że różni się to od innych funkcji hałasu. co udowodnisz, że ma to specjalne właściwości. tylko dlatego, że używasz wielu irracjonalnych liczb, nie czyni go wyjątkowym.
M.kazem Akhgary
2
@Dominic: „Ma lepszą dystrybucję niż podobne funkcje”: należy to udowodnić. tan () jest naprawdę źle uwarunkowany. zarówno tan () w pobliżu pi / 2, jak i sqrt () w pobliżu zera najprawdopodobniej dadzą różne wyniki dla różnych programów sprzętowych, ponieważ wszystkie frakcje (nieliniowe * duże) są oparte na mniej znaczących bitach. Wpłyną na to również małe lub wysokie wartości wejściowe. Również dynamika bitów prawdopodobnie bardzo się różni w zależności od lokalizacji.
Fabrice NEYRET
2
NB: W dzisiejszych czasach GLSL ma liczby całkowite, więc nie ma już powodu, aby nie używać „poważnych” opartych na int generatorów skrótu, gdy wymagany jest rozkład jakości (i dynamika) o podobnych osiągach. (z wyjątkiem bardzo niskiej jakości urządzeń).
Fabrice NEYRET
12

Istnieje również fajna implementacja opisana tutaj przez McEwana i @StefanGustavson, która wygląda jak szum Perlina, ale „nie wymaga żadnej konfiguracji, tj. Nie ma tekstur ani jednolitych tablic. Wystarczy dodać ją do kodu źródłowego modułu cieniującego i wywołać tam, gdzie chcesz”.

Jest to bardzo przydatne, zwłaszcza biorąc pod uwagę fakt, że wcześniejsza implementacja Gustavsona, z którą łączył się @dep, wykorzystuje teksturę 1D, która nie jest obsługiwana w GLSL ES (język cieniowania WebGL).

LarsH
źródło
1
To najlepsza odpowiedź na żądanie typu szumu PO)! Oto bezpośredni link github.com/ashima/webgl-noise . Istnieją wersje 2d, 3d i 4d gotowe jako kod GLSL 120.
user362515
3

Zrób to:

highp float rand(vec2 co)
{
    highp float a = 12.9898;
    highp float b = 78.233;
    highp float c = 43758.5453;
    highp float dt= dot(co.xy ,vec2(a,b));
    highp float sn= mod(dt,3.14);
    return fract(sin(sn) * c);
}

Nie używaj tego:

float rand(vec2 co){
    return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}

Wyjaśnienie znajdziesz w Ulepszeniach kanonicznego jednoliniowego GLSL rand () dla OpenGL ES 2.0

hoangdado
źródło
Przejrzałem artykuł, ale nadal nie jestem pewien, czy 3,14 jest w modprzybliżeniu pi?
Kaan E.
2

Właśnie znalazłem tę wersję szumu 3d dla GPU, podobno jest to najszybszy dostępny:

#ifndef __noise_hlsl_
#define __noise_hlsl_

// hash based 3d value noise
// function taken from https://www.shadertoy.com/view/XslGRr
// Created by inigo quilez - iq/2013
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.

// ported from GLSL to HLSL

float hash( float n )
{
    return frac(sin(n)*43758.5453);
}

float noise( float3 x )
{
    // The noise function returns a value in the range -1.0f -> 1.0f

    float3 p = floor(x);
    float3 f = frac(x);

    f       = f*f*(3.0-2.0*f);
    float n = p.x + p.y*57.0 + 113.0*p.z;

    return lerp(lerp(lerp( hash(n+0.0), hash(n+1.0),f.x),
                   lerp( hash(n+57.0), hash(n+58.0),f.x),f.y),
               lerp(lerp( hash(n+113.0), hash(n+114.0),f.x),
                   lerp( hash(n+170.0), hash(n+171.0),f.x),f.y),f.z);
}

#endif
zrozumiały
źródło
1
Gold Noise (powyżej) jest wtedy oczywiście najszybszy, ponieważ ma znacznie mniej operacji i wykonuje tylko jeden hash - ten wywołuje swoją funkcję hash 8 razy, wykonując zagnieżdżone interpolacje liniowe (lerps). Również ten ma gorszy rozkład, szczególnie przy niskiej precyzji.
Dominic Cerisano
1
No dobra, to wykres typu szumu perlin z shadertoh autorstwa Inigo Quileza. Ładny kod Dominic źle to sprawdzić l8r
com. Prehensible
@Fabrice Wygląda na to, że nie rozumiesz pytania OP, mojej odpowiedzi, mojego kodu ani mojego komentarza. Zgodnie z definicją OP Złoty Hałas jest ciągły - przyjmuje UV i ziarno i udowadnia to, udostępniając moduł cieniujący. Wszystko w twoim komentarzu jest złe. Nadal mylicie funkcje skrótu z pseudolosowymi funkcjami szumu. One nie są takie same. Funkcje hałasu nie wymagają generowania unikalnych identyfikatorów, takich jak funkcje skrótu (rzeczywisty cały punkt mieszania).
Dominic Cerisano,
Proszę, proszę, Dominic, czytaj więcej i dowiedz się więcej, zanim zaczniesz zgłaszać roszczenia do warunków, które według Ciebie rozumiesz, chociaż tak nie jest. Nie tylko te terminy są całkowicie precyzyjne i dobrze zdefiniowane w literaturze, a także pracuję w terenie, ale także PO udowadnia, że ​​zrozumiał te terminy na podstawie podanych później przykładów. Wskazówka: „ciągły” + „hałas” + „jak Perlin”. en.wikipedia.org/wiki/Perlin_noise
Fabrice NEYRET
Ciągły jest tylko przypadek dodania klauzuli pętli, wiele funkcji szumów zapętla się i po pewnym czasie ulega degradacji z powodu zaokrąglania bitów, szczególnie w przypadku grafiki. Chłopaki, to tylko zerwanie komunikacji z tobą, wykorzystaj swój czas na ważne badania.
com. Prehensible
1

Prosta, postrzępiona wersja 1d Perlin, zasadniczo losowy zygzak lfo.

half  rn(float xx){         
    half x0=floor(xx);
    half x1=x0+1;
    half v0 = frac(sin (x0*.014686)*31718.927+x0);
    half v1 = frac(sin (x1*.014686)*31718.927+x1);          

    return (v0*(1-frac(xx))+v1*(frac(xx)))*2-1*sin(xx);
}

Znalazłem również hałas perlin 1-2-3-4d na stronie internetowej właściciela shadertoy inigo quilez perlin, a także voronoi i tak dalej, ma dla niego w pełni szybkie implementacje i kody.

zrozumiały
źródło
1

hash: Obecnie istnieje webGL2.0, więc liczby całkowite są dostępne w (w) GLSL. -> w przypadku wysokiej jakości przenośnego skrótu (przy podobnym koszcie niż brzydkie skróty zmiennoprzecinkowe) możemy teraz zastosować „poważne” techniki mieszania. IQ zaimplementował niektóre w https://www.shadertoy.com/view/XlXcW4 (i więcej)

Na przykład:

  const uint k = 1103515245U;  // GLIB C
//const uint k = 134775813U;   // Delphi and Turbo Pascal
//const uint k = 20170906U;    // Today's date (use three days ago's dateif you want a prime)
//const uint k = 1664525U;     // Numerical Recipes

vec3 hash( uvec3 x )
{
    x = ((x>>8U)^x.yzx)*k;
    x = ((x>>8U)^x.yzx)*k;
    x = ((x>>8U)^x.yzx)*k;

    return vec3(x)*(1.0/float(0xffffffffU));
}
Fabrice NEYRET
źródło
0

Poniżej znajduje się przykład dodawania białego szumu do renderowanej tekstury. Rozwiązaniem jest użycie dwóch tekstur: oryginalnego i czystego białego szumu, takiego jak ten: biały szum wiki

private static final String VERTEX_SHADER =
    "uniform mat4 uMVPMatrix;\n" +
    "uniform mat4 uMVMatrix;\n" +
    "uniform mat4 uSTMatrix;\n" +
    "attribute vec4 aPosition;\n" +
    "attribute vec4 aTextureCoord;\n" +
    "varying vec2 vTextureCoord;\n" +
    "varying vec4 vInCamPosition;\n" +
    "void main() {\n" +
    "    vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" +
    "    gl_Position = uMVPMatrix * aPosition;\n" +
    "}\n";

private static final String FRAGMENT_SHADER =
        "precision mediump float;\n" +
        "uniform sampler2D sTextureUnit;\n" +
        "uniform sampler2D sNoiseTextureUnit;\n" +
        "uniform float uNoseFactor;\n" +
        "varying vec2 vTextureCoord;\n" +
        "varying vec4 vInCamPosition;\n" +
        "void main() {\n" +
                "    gl_FragColor = texture2D(sTextureUnit, vTextureCoord);\n" +
                "    vec4 vRandChosenColor = texture2D(sNoiseTextureUnit, fract(vTextureCoord + uNoseFactor));\n" +
                "    gl_FragColor.r += (0.05 * vRandChosenColor.r);\n" +
                "    gl_FragColor.g += (0.05 * vRandChosenColor.g);\n" +
                "    gl_FragColor.b += (0.05 * vRandChosenColor.b);\n" +
        "}\n";

Udostępniany fragment zawiera parametr uNoiseFactor, który jest aktualizowany przy każdym renderowaniu przez aplikację główną:

float noiseValue = (float)(mRand.nextInt() % 1000)/1000;
int noiseFactorUniformHandle = GLES20.glGetUniformLocation( mProgram, "sNoiseTextureUnit");
GLES20.glUniform1f(noiseFactorUniformHandle, noiseFactor);
klimletov
źródło
0

Przetłumaczyłem jedną z implementacji Java Kena Perlina na GLSL i wykorzystałem ją w kilku projektach ShaderToy.

Poniżej znajduje się interpretacja GLSL, którą zrobiłem:

int b(int N, int B) { return N>>B & 1; }
int T[] = int[](0x15,0x38,0x32,0x2c,0x0d,0x13,0x07,0x2a);
int A[] = int[](0,0,0);

int b(int i, int j, int k, int B) { return T[b(i,B)<<2 | b(j,B)<<1 | b(k,B)]; }

int shuffle(int i, int j, int k) {
    return b(i,j,k,0) + b(j,k,i,1) + b(k,i,j,2) + b(i,j,k,3) +
        b(j,k,i,4) + b(k,i,j,5) + b(i,j,k,6) + b(j,k,i,7) ;
}

float K(int a, vec3 uvw, vec3 ijk)
{
    float s = float(A[0]+A[1]+A[2])/6.0;
    float x = uvw.x - float(A[0]) + s,
        y = uvw.y - float(A[1]) + s,
        z = uvw.z - float(A[2]) + s,
        t = 0.6 - x * x - y * y - z * z;
    int h = shuffle(int(ijk.x) + A[0], int(ijk.y) + A[1], int(ijk.z) + A[2]);
    A[a]++;
    if (t < 0.0)
        return 0.0;
    int b5 = h>>5 & 1, b4 = h>>4 & 1, b3 = h>>3 & 1, b2= h>>2 & 1, b = h & 3;
    float p = b==1?x:b==2?y:z, q = b==1?y:b==2?z:x, r = b==1?z:b==2?x:y;
    p = (b5==b3 ? -p : p); q = (b5==b4 ? -q : q); r = (b5!=(b4^b3) ? -r : r);
    t *= t;
    return 8.0 * t * t * (p + (b==0 ? q+r : b2==0 ? q : r));
}

float noise(float x, float y, float z)
{
    float s = (x + y + z) / 3.0;  
    vec3 ijk = vec3(int(floor(x+s)), int(floor(y+s)), int(floor(z+s)));
    s = float(ijk.x + ijk.y + ijk.z) / 6.0;
    vec3 uvw = vec3(x - float(ijk.x) + s, y - float(ijk.y) + s, z - float(ijk.z) + s);
    A[0] = A[1] = A[2] = 0;
    int hi = uvw.x >= uvw.z ? uvw.x >= uvw.y ? 0 : 1 : uvw.y >= uvw.z ? 1 : 2;
    int lo = uvw.x <  uvw.z ? uvw.x <  uvw.y ? 0 : 1 : uvw.y <  uvw.z ? 1 : 2;
    return K(hi, uvw, ijk) + K(3 - hi - lo, uvw, ijk) + K(lo, uvw, ijk) + K(0, uvw, ijk);
}

Przetłumaczyłem to z Załącznika B z Rozdziału 2 Sprzętu Hałasu Kena Perlina w tym źródle:

https://www.csee.umbc.edu/~olano/s2002c36/ch02.pdf

Oto publiczny odcień, który zrobiłem w Shader Toy, który korzysta z funkcji wysyłania hałasu:

https://www.shadertoy.com/view/3slXzM

Inne dobre źródła, które znalazłem na temat hałasu podczas moich badań, to:

https://thebookofshaders.com/11/

https://mzucker.github.io/html/perlin-noise-math-faq.html

https://rmarcus.info/blog/2018/03/04/perlin-noise.html

http://flafla2.github.io/2014/08/09/perlinnoise.html

https://mrl.nyu.edu/~perlin/noise/

https://rmarcus.info/blog/assets/perlin/perlin_paper.pdf

https://developer.nvidia.com/gpugems/GPUGems/gpugems_ch05.html

Bardzo polecam książkę o shaderach, ponieważ zapewnia ona nie tylko świetne interaktywne wyjaśnienie hałasu, ale także inne koncepcje shaderów.

EDYTOWAĆ:

Może być w stanie zoptymalizować przetłumaczony kod, używając niektórych przyspieszanych sprzętowo funkcji dostępnych w GLSL. Zaktualizuję ten post, jeśli skończę.

Andrew Meservy
źródło
jestem też całkiem pewien, że Perlin / Simplex Noise jest nadal pseudolosowy. Z tego, co pamiętam, interesującą rzeczą jest to, że możesz nakładać i „powiększać” hałas na różnych poziomach, aby wydawał się bardzo płynny. Nie cytuj mnie, ale coś do przemyślenia.
Andrew Meservy,
@Zibri Niestety, nie znam zbyt dobrze prostych poleceń C lub .sh. Wygląda jednak na to, że funkcja jest po prostu generatorem liczb pseudolosowych, a nie funkcją szumu. Pamiętaj również, że shadery pikseli glsl działają bezpośrednio na procesorze. Nie będą mieli dostępu do żadnego z tych dodatkowych bibliotek lub możliwości procesora, które mogą być dostępne w C
Andrew Meservy
Book Of Shaders ma świetne wyjaśnienie, w jaki sposób Simplex Noise jest bardziej wydajną wersją Perlin Noise ze względu na wypaczanie siatki i mniej niezbędnych obliczeń na punkt. Zdecydowanie warte przeczytania.
Andrew Meservy,
zobacz także rozdziały na temat fraktalnego ruchu Browna i voronoise
Andrew Meservy
Andrew Meservy: nie potrzeba bibliotek ... moja funkcja szumu jest bardzo prosta: 2 64-bitowe inty to stan x (n) i x (n-1). Prosta i szybka formuła to x (n + 1) = ROTR ( x (n) + x (n-1), 8). jeśli sklonujesz mojego gita i uruchomisz go, zobaczysz go w akcji.
Zibri,