it-swarm.com.de

Random/Noise-Funktionen für GLSL

Da sich die GPU-Treiberhersteller normalerweise nicht darum kümmern, noiseX in GLSL zu implementieren, suche ich nach einem "Grafik-Randomization-Swiss Army Knife" Utility-Funktionssatz, der vorzugsweise für die Verwendung in GPU-Shadern optimiert ist. Ich bevorzuge GLSL, aber Code, den jede Sprache für mich bietet, kann ich auch selbst in GLSL übersetzen.

Konkret würde ich erwarten:

a) Pseudozufallsfunktionen - N-dimensionale, gleichmäßige Verteilung über [-1,1] oder über [0,1], berechnet aus dem M-dimensionalen Startwert (idealerweise ein beliebiger Wert, aber ich bin damit einverstanden das Saatgut für eine gleichmäßige Ergebnisverteilung auf z. B. 0..1 zurückgehalten wird). So 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 - wieder N-dimensional, + - gleichmäßige Verteilung, mit eingeschränktem Wertesatz und gut aussehend (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 am eifrigsten für eine vorgefertigte Lösung entscheiden, aber ich würde auch Antworten wie "hier ist ein sehr guter, effizienter 1D Rand (), und lassen Sie mich Ihnen erklären, wie Sie einen guten N-dimensionalen Rand () darüber erstellen ... ".

151
Kos

Für sehr einfaches pseudo-zufällig aussehendes Zeug 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 beliebigem PRNG erzeugen. Laden Sie diese dann wie üblich hoch und probieren Sie die Werte in Ihrem Shader. Ich kann später ein Codebeispiel aufspüren, wenn Sie möchten.

Checke diese Datei für GLSL-Implementierungen von Perlin- und Simplex-Rauschen von Stefan Gustavson aus. 

241
appas

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, die sich auf dem von Ihnen angegebenen Link befindet, 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 etwa halb so schnell. 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

Eine Sammlung von sowohl texturlosen als auch texturverwendenden Versionen von Rauschen finden Sie hier (nur unter Verwendung von 2D-Texturen):

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

Wenn Sie spezielle Fragen haben, senden Sie mir eine E-Mail (meine E-Mail-Adresse befindet sich in den classicnoise*.glsl-Quellen.)

69

Es scheint mir, dass Sie eine einfache Integer-Hash-Funktion verwenden und das Ergebnis in die Mantisse eines Floats einfügen können. IIRC, die GLSL-Spezifikation, garantiert 32-Bit-Ganzzahlen ohne Vorzeichen 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 ausprobierte, genau wie statisch aus, überhaupt keine sichtbaren Muster. Im Gegensatz dazu weist das populäre Sin/Fra-Snippet bei gleichen Eingaben ziemlich diagonale Linien auf meiner GPU auf.

Ein Nachteil ist, dass es GLSL v3.30 erfordert. Und obwohl es schnell genug scheint, habe ich seine Leistung nicht empirisch quantifiziert. Der Shader-Analysator von AMD beansprucht 13,33 Pixel pro Takt für die vec2-Version auf einer HD5870. Demgegenüber stehen 16 Pixel pro Takt für das Sin/Fra-Snippet. Es ist also sicherlich etwas langsamer.

Hier ist meine Implementierung. Ich habe es in verschiedenen Abwandlungen der Idee gelassen, um die Ableitung eigener Funktionen zu erleichtern.

/*
    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:

Output of random(vec3) in static.frag

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

63
Spatial

Goldrauschen

// Gold Noise ©2015 [email protected] 
//  - based on the Golden Ratio, PI and Square Root of Two
//  - superior distribution
//  - fastest noise generator function
//  - works with all chipsets (including low precision)

float PHI = 1.61803398874989484820459 * 00000.1; // Golden Ratio   
float PI  = 3.14159265358979323846264 * 00000.1; // PI
float SQ2 = 1.41421356237309504880169 * 10000.0; // Square Root of Two

float gold_noise(in vec2 coordinate, in float seed){
    return fract(tan(distance(coordinate*(seed+PHI), vec2(PHI, PI)))*SQ2);
}

Sehen Sie Gold Noise jetzt in Ihrem Browser!

 enter image description here

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

 enter image description here

Die @appas-Funktion ist ebenfalls unvollständig, da kein Startwert bereitgestellt wird (uv ist kein Startwert - für jeden Frame gleich) und funktioniert nicht mit Chipsätzen mit niedriger Genauigkeit. Gold Noise läuft standardmäßig mit niedriger Genauigkeit (viel schneller).

18

Es gibt auch eine Nice-Implementierung, die hier von McEwan und @StefanGustavson beschrieben wird, die wie Perlin-Rauschen aussieht, aber "keine Einrichtung erfordert, dh keine Texturen oder einheitlichen Arrays. Fügen Sie sie einfach dem Shader-Quellcode hinzu und rufen Sie auf es wo immer du willst ".

Das ist sehr praktisch, vor allem, da Gustavsons frühere Implementierung, mit der @dep verlinkt wurde, eine 1D-Textur verwendet, die nicht in GLSL ES unterstützt (die Shader-Sprache von WebGL) ist.

11
LarsH

Ich habe gerade diese Version des 3D-Rauschens für GPU gefunden. Alledged ist es die schnellste verfügbare Version:

#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
2
com.prehensible

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-Lärm auf Shadertoy-Besitzer inigo quilez perlin Tutorial-Website gefunden, und voronoi und so weiter hat er vollständige schnelle Implementierungen und Codes für sie. 

1
com.prehensible

Nachfolgend finden Sie ein Beispiel, wie Sie der gerenderten Textur ein weißes Rauschen hinzufügen. Die Lösung besteht darin, zwei Texturen zu verwenden: das ursprüngliche und das reine weiße Rauschen, wie dieses: wiki white noise

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 jeder Wiedergabe von der Hauptanwendung aktualisiert wird:

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

hash: Heutzutage ist webGL2.0 so, dass ganze Zahlen in (w) GLSL .-> verfügbar sind. Für qualitativ hochwertigen portablen Hash (zu ähnlichen Kosten als hässliche Float-Hashes) können wir jetzt "ernsthafte" Hashtechniken verwendenIQ 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));
}
0
Fabrice NEYRET

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

Nachfolgend meine GLSL-Interpretation:

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 Perlin's Noise Hardware an dieser Quelle übersetzt:

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

Hier ist ein öffentlicher Farbton, den ich bei Shader Toy gemacht habe, der die veröffentlichte Geräuschfunktion verwendet:

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

Ich kann mich nicht recht erinnern, aber ich denke, seit ich 1.0/Noise gemacht habe, macht dieses Simplex-Noise statt echtem Perlin-Noise.

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 wärmstens empfehlen, da es nicht nur eine großartige interaktive Erklärung für das Rauschen bietet, sondern auch andere Shader-Konzepte.

0
Andrew Meservy

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 das nicht:

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

Die Erklärung finden Sie in Verbesserungen am kanonischen Einzeiler GLSL Rand () für OpenGL ES 2.

0
hoangdado