Zufalls- / Rauschfunktionen für GLSL

179

Da sich die Anbieter von GPU-Treibern normalerweise nicht die Mühe machen, sie noiseXin GLSL zu implementieren , suche ich nach einem Dienstprogramm mit der Funktion "Grafik-Randomisierung, Schweizer Taschenmesser" , das vorzugsweise für die Verwendung in GPU-Shadern optimiert ist. Ich bevorzuge GLSL, aber Code, den jede Sprache für mich tun kann, ist in Ordnung, wenn ich ihn selbst in GLSL übersetze.

Insbesondere würde ich erwarten:

a) Pseudozufallsfunktionen - N-dimensionale, gleichmäßige Verteilung über [-1,1] oder über [0,1], berechnet aus M-dimensionalem Keim (idealerweise ein beliebiger Wert, aber ich bin damit einverstanden, dass der Keim zurückgehalten wird zum Beispiel 0..1 für eine gleichmäßige Ergebnisverteilung). Etwas wie:

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) Kontinuierliches Rauschen wie Perlin-Rauschen - wiederum N-dimensional, + - gleichmäßige Verteilung mit eingeschränktem Wertesatz und gutem Aussehen (einige Optionen zum Konfigurieren des Erscheinungsbilds wie Perlin-Pegel könnten ebenfalls nützlich sein). Ich würde Unterschriften erwarten wie:

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

Ich beschäftige mich nicht sehr mit der Theorie der Zufallszahlengenerierung, daher würde ich mich sehr gerne für eine vorgefertigte Lösung entscheiden , aber ich würde auch Antworten wie "Hier ist ein sehr guter, effizienter 1D-Rand ()" begrüßen und mich erklären lassen Sie, wie man einen guten N-dimensionalen Rand () darüber macht ... " .

Kos
quelle

Antworten:

263

Für sehr einfache pseudozufällig aussehende Dinge verwende ich diesen Oneliner, den ich irgendwo im Internet gefunden habe:

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

Sie können auch eine Rauschtextur mit einem beliebigen PRNG generieren, diese dann wie gewohnt hochladen und die Werte in Ihrem Shader abtasten. Ich kann später ein Codebeispiel ausgraben, wenn Sie möchten.

In dieser Datei finden Sie auch GLSL-Implementierungen von Perlin- und Simplex-Rauschen von Stefan Gustavson.

Appas
quelle
13
Wie benutzt man vec2 co? ist es die Reichweite? Samen?
Ross
12
Achten Sie bei diesem Algorithmus (z. B. ARM Mali von S3) auf Gleitkomma-Fragment-Shader mit geringer Genauigkeit: stackoverflow.com/questions/11293628/… . Das Projekt github.com/ashima/webgl-noise scheint keine Lowp-Probleme zu haben.
PT
4
FWIW beschriebene Funktion wird hier genauer diskutiert hier .
Loomchild
3
Zu Ihrer Information: Die Verteilung dieser Funktion ist schrecklich.
Tara
3
Ich bin ein Neuling in GLSL. Kann jemand erklären, warum co.xystatt co?
Kelin
83

Mir fällt ein, dass Sie eine einfache Ganzzahl-Hash-Funktion verwenden und das Ergebnis in die Mantisse eines Floats einfügen könnten. IIRC Die GLSL-Spezifikation garantiert vorzeichenlose 32-Bit-Ganzzahlen und eine IEEE-Binär-32-Float-Darstellung, sodass sie perfekt portierbar sein sollte.

Ich habe es gerade versucht. Die Ergebnisse sind sehr gut: Es sieht bei jeder Eingabe, die ich versucht habe, genau wie statisch aus, überhaupt keine sichtbaren Muster. Im Gegensatz dazu hat das beliebte Sin / Fract-Snippet bei gleichen Eingaben ziemlich ausgeprägte diagonale Linien auf meiner GPU.

Ein Nachteil ist, dass GLSL v3.30 erforderlich ist. Und obwohl es schnell genug zu sein scheint, habe ich seine Leistung nicht empirisch quantifiziert. AMDs Shader Analyzer beansprucht 13,33 Pixel pro Takt für die vec2-Version auf einem HD5870. Kontrast zu 16 Pixel pro Takt für das Sin / Fract-Snippet. Es ist also sicherlich etwas langsamer.

Hier ist meine Implementierung. Ich habe es in verschiedenen Permutationen der Idee belassen, um es einfacher zu machen, eigene Funktionen daraus abzuleiten.

/*
    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 );
}

Bildschirmfoto:

Ausgabe von random (vec3) in static.frag

Ich habe den Screenshot in einem Bildbearbeitungsprogramm überprüft. Es gibt 256 Farben und der Durchschnittswert beträgt 127, was bedeutet, dass die Verteilung gleichmäßig ist und den erwarteten Bereich abdeckt.

Räumlich
quelle
17
+1 für eine gute Idee und Umsetzung. Ich würde die Behauptung in Frage stellen, dass die Verteilung gleichmäßig sein muss (im engeren Sinne), da es 256 Farben gibt und der Durchschnittswert 127 beträgt. Es mag einheitlich sein, aber ich glaube, wir wissen das noch nicht. Beispielsweise könnte eine Glockenkurvenverteilung den gleichen Durchschnitt und die gleiche Anzahl von Farben haben, wäre aber nicht einheitlich.
LarsH
Ich habe dies aus dem von @LarsH angegebenen Grund abgelehnt.
Autumnsault
Nun, es ist gut genug für die meisten Anwendungen, die keine Einheitlichkeit benötigen . :-)
itmuckel
5
Nach meiner Wahrnehmung des Histogramms scheint es sehr einheitlich zu sein. Ich würde sagen, es ist gut genug für die meisten Anwendungen, die ebenfalls Einheitlichkeit benötigen. (Die einzigen Werte, die weniger als die anderen generiert zu werden scheinen, sind 0 und 255)
Leviathanbadger
Vielen Dank. Meine Wahrscheinlichkeit ist rostig. Nachdem Sie sich den GCN-Befehlssatz angesehen haben, sollte dies auf neuerer Hardware sehr schnell sein, da sie Bitfeldoperationen in ihren Befehlssätzen direkt unterstützen. Die Tests, die ich durchgeführt habe, wurden auf älterer Hardware ausgeführt.
Spatial
73

Die Implementierung von Gustavson verwendet eine 1D-Textur

Nein, nicht seit 2005. Es ist nur so, dass die Leute darauf bestehen, die alte Version herunterzuladen. Die Version auf dem von Ihnen angegebenen Link verwendet nur 8-Bit-2D-Texturen.

Die neue Version von Ian McEwan von Ashima und mir verwendet keine Textur, läuft jedoch auf typischen Desktop-Plattformen mit viel Texturbandbreite mit etwa der halben Geschwindigkeit. Auf mobilen Plattformen ist die texturlose Version möglicherweise schneller, da die Texturierung häufig einen erheblichen Engpass darstellt.

Unser aktiv gepflegtes Quell-Repository ist:

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

Hier finden Sie eine Sammlung der texturlosen und texturverwendenden Versionen von Rauschen (nur mit 2D-Texturen):

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

Wenn Sie spezielle Fragen haben, können Sie mir gerne direkt eine E-Mail senden (meine E-Mail-Adresse finden Sie in den classicnoise*.glslQuellen).

Stefan Gustavson
quelle
4
Ja, die Implementierung, auf die ich mich beziehe, Ihr Code auf davidcornette.com, mit dem @dep verknüpft ist, verwendet eine 1D-Textur: glBindTexture(GL_TEXTURE_1D, *texID);usw. Es ist nicht klar, was Sie unter "dem von Ihnen angegebenen Link" verstehen, da Sie aus meiner Antwort zitieren Diese Antwort war jedoch nicht mit Ihrer Implementierung verknüpft. Ich werde meine Antwort aktualisieren, um zu verdeutlichen, worauf ich mich beziehe, und um die neuen Informationen wiederzugeben, die Sie gegeben haben. Menschen als "darauf bestehen", die alte Version herunterzuladen, ist eine Verzerrung, die Sie nicht gutschreiben.
LarsH
1
PS Vielleicht möchten Sie David Cornette schreiben (er hat Kontaktinformationen unter davidcornette.com ) und ihn bitten, seinen Link auf davidcornette.com/glsl/links.html zu ändern, um einen Link zu Ihrem Quell-Repo zu erstellen . Ich werde ihm auch eine E-Mail schicken.
LarsH
1
PPS Können Sie klarstellen, welche Version nur 8-Bit-2D-Texturen verwendet? Klingt wie es eine gute Option für bestimmte Plattformen sein könnte ...
LarsH
31

Goldrauschen

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

Sehen Sie jetzt Gold Noise in Ihrem Browser!

Geben Sie hier die Bildbeschreibung ein

Diese Funktion hat die Zufallsverteilung gegenüber der aktuellen Funktion in der Antwort von @appas vom 9. September 2017 verbessert:

Geben Sie hier die Bildbeschreibung ein

Die @ appas-Funktion ist ebenfalls unvollständig, da kein Seed bereitgestellt wird (UV ist kein Seed - für jeden Frame gleich) und funktioniert nicht mit Chipsätzen mit geringer Genauigkeit. Gold Noise wird standardmäßig mit geringer Genauigkeit ausgeführt (viel schneller).

Dominic Cerisano
quelle
Vielen Dank für die Veröffentlichung. Würden Sie in Betracht ziehen, eine ausführbare Version zu veröffentlichen, z. B. auf shadertoy.com, damit die Benutzer sie im Browser ausprobieren können?
LarsH
@snb Shadertoy.com wird diesen Monat gewartet. Haben Sie etwas Geduld. Außerdem habe ich die Forderung nach irrationalen Startwerten im dortigen Code klar dokumentiert. Da Goldrauschen einen Skalar zurückgibt, ist das Konstruieren von Vektoren damit trivial und auch im Code dokumentiert.
Dominic Cerisano
7
Ich denke nicht, dass dies anders ist als andere Rauschfunktionen. Was ist Ihr Beweis, dass dies besondere Eigenschaften hat. Nur weil Sie eine Reihe irrationaler Zahlen verwenden, ist dies nichts Besonderes.
M. Kazem Akhgary 6.
2
@Dominic: "Es hat eine überlegene Verteilung gegenüber ähnlichen Funktionen": Dies muss bewiesen werden. tan () ist wirklich schlecht konditioniert. Sowohl tan () in der Nähe von pi / 2 als auch sqrt () in der Nähe von Null führen sehr wahrscheinlich zu unterschiedlichen Ergebnissen auf verschiedenen Hardwares, da alle Brüche (nicht linear * groß) auf weniger signifikanten Bits basieren. Kleine oder hohe Eingabewerte wirken sich ebenfalls aus. Außerdem variiert die Bitdynamik wahrscheinlich auch stark je nach Standort.
Fabrice NEYRET
1
NB: Heutzutage hat GLSL Ganzzahlen, daher gibt es keinen Grund mehr, keine "ernsthaften" int-basierten Hash-Generatoren zu verwenden, wenn eine Qualitätsverteilung (und -dynamik) mit ähnlichen Leistungen erforderlich ist. (ausgenommen für sehr Low-End-Geräte).
Fabrice NEYRET
12

Es gibt auch eine nette Implementierung, die hier von McEwan und @StefanGustavson beschrieben wird und wie Perlin-Rauschen aussieht, aber "kein Setup erfordert, dh keine Texturen oder einheitlichen Arrays. Fügen Sie sie einfach Ihrem Shader-Quellcode hinzu und rufen Sie sie auf, wo immer Sie wollen".

Dies ist sehr praktisch, insbesondere angesichts der Tatsache, dass die frühere Implementierung von Gustavson, mit der @dep verknüpft ist, eine 1D-Textur verwendet, die in GLSL ES (der Shader-Sprache von WebGL) nicht unterstützt wird .

LarsH
quelle
1
Dies ist die beste Antwort auf die b) Rauschartanforderung von OP! Hier ist ein direkter Link github.com/ashima/webgl-noise . Es gibt 2d-, 3d- und 4d-Versionen als GLSL 120-Code.
user362515
3

Verwenden Sie dies:

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

Verwenden Sie dies nicht:

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

Die Erklärung finden Sie unter Verbesserungen des kanonischen einzeiligen GLSL rand () für OpenGL ES 2.0

Hoangdado
quelle
Ich habe den Artikel überflogen, bin mir aber immer noch nicht sicher, ob 3.14 modeine Annäherung an pi ist.
Kaan E.
2

Ich habe gerade diese Version von 3D-Rauschen für die GPU gefunden. Angeblich ist sie die schnellste auf dem Markt:

#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
verständlich
quelle
1
Gold Noise (oben) ist dann offensichtlich am schnellsten, da es weitaus weniger Operationen hat und nur einen Hash ausführt - dieser ruft seine Hash-Funktion 8 Mal auf, während verschachtelte lineare Interpolationen (Lerps) ausgeführt werden. Auch dieser hat eine schlechtere Verteilung, insbesondere bei geringer Präzision.
Dominic Cerisano
1
Oh, guter Punkt, es ist ein Perlin Noise Type Graph von Shadertoh von Inigo Quilez. Netter Code Dominic wird es überprüfen l8r
com.prehensible
@Fabrice Sie scheinen die Frage des OP, meine Antwort, meinen Code oder meinen Kommentar nicht zu verstehen. Gold Noise ist nach der OP-Definition kontinuierlich - es akzeptiert UV und einen Startwert und beweist dies durch die Bereitstellung eines Shaders. Alles an Ihrem Kommentar ist falsch. Sie verwechseln immer wieder Hash-Funktionen mit pseudozufälligen Rauschfunktionen. Sie sind nicht gleich. Rauschfunktionen müssen keine eindeutigen Bezeichner wie Hash-Funktionen generieren (der eigentliche ganze Punkt des Hashings).
Dominic Cerisano
Bitte, bitte, bitte, Dominic, lesen Sie mehr und lernen Sie mehr, bevor Sie Dinge über Begriffe behaupten, die Sie zu verstehen glauben, obwohl dies nicht der Fall ist. Nicht nur diese Begriffe sind absolut präzise und in der Literatur gut definiert, und ich arbeite auf dem Gebiet, sondern auch das OP beweist, dass er die Begriffe anhand der Beispiele verstanden hat, die er danach gegeben hat. Hinweis: "kontinuierlich" + "Rauschen" + "wie Perlin". en.wikipedia.org/wiki/Perlin_noise
Fabrice NEYRET
Kontinuierlich ist nur der Fall, dass eine Schleifenklausel hinzugefügt wird. Viele Rauschfunktionen werden aufgrund der Bitrundung speziell für Grafiken nach einer bestimmten Weise wiederholt und verschlechtert. Leute, es ist nur eine Kommunikation, die von dir unterbrochen wird. Nutze deine Zeit für wichtige Nachforschungen.
com.prehensible
1

Eine gerade, gezackte Version von 1d Perlin, im Wesentlichen ein zufälliger lfo-Zickzack.

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

Ich habe auch 1-2-3-4d Perlin Rauschen auf Shadertoy Besitzer Inigo Quilez Perlin Tutorial Website gefunden, und Voronoi und so weiter, er hat voll schnelle Implementierungen und Codes für sie.

verständlich
quelle
1

Hash: Heutzutage ist webGL2.0 vorhanden, sodass in (w) GLSL Ganzzahlen verfügbar sind. -> Für hochwertigen tragbaren Hash (zu ähnlichen Kosten wie hässliche Float-Hashes) können wir jetzt "ernsthafte" Hashing-Techniken verwenden. IQ implementierte einige in https://www.shadertoy.com/view/XlXcW4 (und mehr)

Z.B:

  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
quelle
0

Unten sehen Sie ein Beispiel, wie Sie der gerenderten Textur weißes Rauschen hinzufügen. Die Lösung besteht darin, zwei Texturen zu verwenden: ursprüngliches und reines weißes Rauschen, wie dieses: weißes Wiki-Rauschen

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

Das gemeinsam genutzte Fragment enthält den Parameter uNoiseFactor, der bei jedem Rendern durch die Hauptanwendung aktualisiert wird:

float noiseValue = (float)(mRand.nextInt() % 1000)/1000;
int noiseFactorUniformHandle = GLES20.glGetUniformLocation( mProgram, "sNoiseTextureUnit");
GLES20.glUniform1f(noiseFactorUniformHandle, noiseFactor);
klimletov
quelle
0

Ich habe eine der Java-Implementierungen von Ken Perlin in GLSL übersetzt und in einigen Projekten auf ShaderToy verwendet.

Unten ist die GLSL-Interpretation, die ich gemacht habe:

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

Ich habe es aus Anhang B aus Kapitel 2 von Ken Perlins Noise Hardware an dieser Quelle übersetzt:

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

Hier ist ein öffentlicher Schatten, den ich auf Shader Toy gemacht habe und der die Funktion für gepostete Geräusche verwendet:

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

Einige andere gute Quellen, die ich während meiner Recherche zum Thema Lärm gefunden habe, sind:

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

Ich kann das Buch der Shader nur empfehlen, da es nicht nur eine großartige interaktive Erklärung des Rauschens bietet, sondern auch andere Shader-Konzepte.

BEARBEITEN:

Möglicherweise können Sie den übersetzten Code mithilfe einiger der in GLSL verfügbaren hardwarebeschleunigten Funktionen optimieren. Wird diesen Beitrag aktualisieren, wenn ich dies am Ende tue.

Andrew Meservy
quelle
Außerdem bin ich mir ziemlich sicher, dass Perlin / Simplex Noise immer noch pseudozufällig ist. Soweit ich mich erinnere, ist das Interessante, dass Sie das Rauschen auf verschiedenen Ebenen überlagern und "zoomen" können, damit es sehr nahtlos erscheint. Zitiere mich nicht dazu, aber etwas zum Nachdenken.
Andrew Meservy
@ Zibri Leider bin ich mit geraden C- oder .sh-Befehlen nicht besonders vertraut. Aber es sieht so aus, als wäre die Funktion einfach ein Pseudozufallszahlengenerator und keine Rauschfunktion. Denken Sie auch daran, dass glsl-Pixel-Shader direkt auf der GPU ausgeführt werden. Sie haben keinen Zugriff auf eine dieser zusätzlichen Bibliotheken oder CPU-Funktionen, die möglicherweise in C verfügbar sind.
Andrew Meservy
Das Buch der Shader enthält eine großartige Erklärung dafür, wie Simplex Noise eine effizientere Version von Perlin Noise ist, da das Raster verzerrt ist und weniger notwendige Berechnungen pro Punkt erforderlich sind. Auf jeden Fall eine Lektüre wert.
Andrew Meservy
Siehe auch die Kapitel über fraktale Brownsche Bewegung und Voronoise
Andrew Meservy
Andrew Meservy: Keine Bibliotheken erforderlich ... meine Rauschfunktion ist sehr einfach: 2 64-Bit-Ints sind der Zustand x (n) und x (n-1). Die einfache und schnelle Formel lautet x (n + 1) = ROTR ( x (n) + x (n-1), 8). Wenn Sie meinen Git klonen und ausführen, werden Sie ihn in Aktion sehen.
Zibri