Fonctions Random / noise pour GLSL

comme les fournisseurs de pilotes GPU ne prennent généralement pas la peine d'implémenter noiseX dans GLSL, je suis à la recherche d'un " randomisation graphique Swiss army knife " jeu de fonction utilitaire, de préférence optimisé pour une utilisation dans les shaders GPU. Je préfère GLSL, mais coder n'importe quelle langue fera l'affaire pour moi, je suis d'accord pour le traduire moi-même en GLSL.

plus précisément, je m'attendais à:

a) Pseudo-aléatoires, fonctions de - N-dimensionnel, distribution uniforme sur [-1,1] ou sur [0,1], calculé à partir de la graine m-dimensionnel (idéalement être n'importe quelle valeur, mais je suis D'accord pour avoir la graine limitée à, disons, 0..1 pour une répartition uniforme des résultats). Quelque chose comme:

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) Continue de bruit comme le Bruit de Perlin - encore une fois, à N dimensions, +- distribution uniforme, avec la contrainte d'un ensemble de valeurs et, ainsi, à la recherche de bonnes (certaines options permettant de configurer l'apparence comme Perlin les niveaux pourraient être utiles). Je m'attendais à des signatures comme:

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

Je ne suis pas très intéressé par la théorie de la génération de nombres aléatoires, donc je suis très impatient d'aller pour une solution pré-faite , mais j'apprécierais aussi des réponses comme " voici un très bon, efficace 1D rand(), et laissez-moi vous expliquer comment faire un bon rand n-dimensionnel() sur le dessus de lui..." .

145
demandé sur Kos 2010-11-17 02:50:50

9 réponses

pour des choses très simples à l'apparence de pseudorandom, j'utilise cet oneliner que j'ai trouvé quelque part sur internet:

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

vous pouvez également générer une texture de bruit en utilisant N'importe quel PRNG que vous aimez, puis téléchargez ceci de la manière normale et échantillonnez les valeurs dans votre shader; je peux creuser un échantillon de code plus tard si vous voulez.

également, consultez ce fichier pour les implémentations GLSL de Perlin et Simplex noise, par Stefan Gustavson.

234
répondu appas 2010-11-25 09:12:38

Gustavson de la mise en œuvre utilise une texture 1D

non, pas depuis 2005. C'est juste que les gens insistent pour télécharger l'ancienne version. La version qui se trouve sur le lien que vous avez fourni n'utilise que des textures 2D 8 bits.

la nouvelle version par Ian McEwan D'Ashima et moi-même n'utilise pas une texture, mais fonctionne à environ la moitié de la vitesse sur les plates-formes de bureau typiques avec beaucoup de bande passante de texture. Sur mobile plates-formes, la version sans texte pourrait être plus rapide parce que la texturation est souvent un goulot d'étranglement important.

notre dépôt source maintenu activement est:

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

une collection des versions textureless et texture-using du bruit est ici (en utilisant seulement des textures 2D):

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

si vous avez des questions précises, n'hésitez pas à m'envoyer un courriel directement (mon adresse courriel se trouve dans les sources classicnoise*.glsl ).)

67
répondu Stefan Gustavson 2013-12-01 03:18:09

il me vient à l'esprit que vous pourriez utiliser une simple fonction de hachage entier et insérer le résultat dans le mantissa d'un flotteur. IIRC la spécification GLSL garantit des entiers 32 bits non signés et la représentation de flotteurs binary32 D'IEEE donc elle devrait être parfaitement portable.

j'ai essayé tout à l'heure. Les résultats sont très bons: il ressemble exactement comme statique avec chaque entrée que j'ai essayé, pas de modèles visibles du tout. En revanche, le Sin/fract populaire snippet a assez prononcé diagonal les lignes sur mon GPU donné les mêmes entrées.

un inconvénient est qu'il nécessite GLSL v3.30 ans. Et bien que cela semble assez rapide, je n'ai pas quantifié empiriquement ses performances. L'Analyseur de shaders D'AMD réclame 13.33 pixels par horloge pour la version vec2 sur un HD5870. Contraste avec 16 pixels par horloge pour le Sin / fract snippet. C'est certainement un peu plus lent.

Voici mon implémentation. Je l'ai laissé dans diverses permutations de l'idée de rendre plus facile à tirer vos propres fonctions.

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

Capture d'écran:

Output of random(vec3) in static.frag

j'ai inspecté la capture d'écran dans un programme d'édition d'image. Il y a 256 couleurs et la valeur moyenne est de 127, ce qui signifie que la distribution est uniforme et couvre la gamme attendue.

58
répondu Spatial 2013-07-04 23:40:13

Or Bruit

// Gold Noise ©2015 dcerisano@standard3d.com 
//  - based on the Golden Ratio, PI and Square Root of Two
//  - superior distribution
//  - fastest noise generator function
//  - works with all chipsets (including low precision)

precision lowp    float;

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

voir Gold Noise dans votre navigateur à l'heure actuelle!

enter image description here

cette fonction a amélioré la distribution aléatoire par rapport à la fonction actuelle dans la réponse de @appas au 9 Septembre 2017:

enter image description here

le la fonction @appas est également incomplète, étant donné qu'il n'y a pas de graine fournie (uv n'est pas une graine - même pour chaque cadre), et ne fonctionne pas avec des chipsets de faible précision. Or le Bruit fonctionne à faible précision par défaut (beaucoup plus rapide).

15
répondu Dominic Cerisano 2018-07-31 18:34:51

il y a aussi une belle implémentation décrite ici par McEwan et @StefanGustavson qui ressemble à Perlin noise, mais" ne nécessite pas de configuration, c.-à-d. pas de textures ni de matrices uniformes. Il suffit de l'ajouter à votre code source shader et de l'appeler où vous voulez".

c'est très pratique, d'autant plus que L'implémentation antérieure de Gustavson, à laquelle @dep est liée, utilise une texture 1D, qui est non prise en charge dans GLSL ES (le langage de shader de WebGL).

11
répondu LarsH 2017-05-23 12:18:19

vient de trouver cette version de bruit 3d pour GPU, alledgedly il est le plus rapide disponible:

#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
répondu com.prehensible 2014-02-06 13:49:31

une version droite et déchiquetée de 1d Perlin, essentiellement un zigzag LFO aléatoire.

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

j'ai aussi trouvé 1-2-3-4D Perlin noise sur le site Web du propriétaire de shadertoy inigo quilez perlin tutorial, et voronoi et ainsi de suite, il a des implémentations et des codes rapides pour eux.

0
répondu com.prehensible 2018-07-16 10:12:37

s'il vous plaît voir ci-dessous un exemple comment ajouter du bruit blanc à la texture rendue. La solution est d'utiliser deux textures: bruit blanc original et pur, comme celui-ci: bruit blanc 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";

le fragment partagé contient le paramètre uNoiseFactor qui est mis à jour sur chaque rendu par application principale:

float noiseValue = (float)(mRand.nextInt() % 1000)/1000;
int noiseFactorUniformHandle = GLES20.glGetUniformLocation( mProgram, "sNoiseTextureUnit");
GLES20.glUniform1f(noiseFactorUniformHandle, noiseFactor);
0
répondu klimletov 2018-07-16 10:13:10

de hachage: De nos jours webGL2.0 est-il alors des entiers sont disponibles dans (w)GLSL. - >pour le hachage portable de qualité (à un coût similaire à celui des hachures flottantes laides), nous pouvons désormais utiliser des techniques de hachage "sérieuses". IQ mis en œuvre certains dans https://www.shadertoy.com/view/XlXcW4 (et plus)

par exemple:

  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
répondu Fabrice NEYRET 2018-09-06 15:28:03