Question

En tant que fournisseurs de pilotes GPU ne se soucient généralement pas de mettre en œuvre noiseX en GLSL, je suis à la recherche d'un « graphiques couteau randomization armée suisse » jeu de fonction d'utilité, de préférence optimisés pour utiliser dans les shaders GPU . Je préfère GLSL, mais le code ne importe quelle langue fera pour moi, je suis ok avec le traduire moi-même à GLSL.

Plus précisément, je pense:

a) fonctions pseudo-aléatoires - répartition à N dimensions, uniforme sur [-1,1] ou sur [0,1], calculé à partir de graines M-dimensionnelle (idéalement être une valeur quelconque, mais je suis OK d'avoir la semence retenue, disons, 0..1 pour une distribution uniforme de résultat). 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) Continuous bruit comme Perlin Noise - encore une fois, à N dimensions, + - distribution uniforme, ensemble contrainte de valeurs et, bien, en regardant bien (quelques options pour configurer l'apparence comme les niveaux Perlin pourrait être utile aussi). J'attends des signatures comme:

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

Je ne suis pas très bien dans la théorie de la génération de nombres aléatoires, donc je plus aller avec impatience une solution pré-faites , mais je voudrais aussi apprécier des réponses comme "est ici un très bon, rand efficace 1D (), et laissez-moi vous expliquer comment faire un bon rand N dimensions () sur le dessus de celui-ci ... ".

Était-ce utile?

La solution

Pour des trucs prospectifs pseudo-aléatoire très simple, j'utilise cette oneliner que j'ai trouvé sur internet quelque part:

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 tous les PRNG que vous voulez, puis télécharger ce de la façon normale et l'échantillon des valeurs dans votre shaders; Je peux déterrer un exemple de code plus tard si vous le souhaitez.

En outre, consultez ce fichier pour les implémentations GLSL du bruit Perlin et Simplex , par Stefan Gustavson.

Autres conseils

  

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

Non, il n'a pas, pas depuis 2005. Il est juste que les gens insistent sur le téléchargement de l'ancienne version. La version qui est sur le lien que vous avez fourni utilise des textures 2D seulement 8 bits.

La nouvelle version par Ian McEwan de Ashima et moi-même ne pas utiliser une texture, mais tourne autour de la moitié de la vitesse sur les plates-formes de bureau typique avec beaucoup de bande passante de texture. Sur les plates-formes mobiles, la version peut être plus rapide sans texture, car texturation est souvent un goulot d'étranglement important.

Notre référentiel source activement maintenu est:

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

Une collection des deux versions et l'utilisation sans texture texture de bruit est ici (en utilisant uniquement des textures 2D):

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

Si vous avez des questions, ne hésitez pas à me contacter directement (mon adresse e-mail se trouve dans les sources de classicnoise*.glsl.)

Il me semble que vous pouvez utiliser une simple fonction de hachage entier et insérer le résultat dans la mantisse d'un flotteur. IIRC la spécification GLSL garantit des entiers non signés 32 bits et IEEE binary32 Représentation du flotteur, il devrait être parfaitement portable.

J'ai donné cette solution tout à l'heure. Les résultats sont très bons: il ressemble exactement statique avec chaque entrée j'ai essayé, aucun motif visible. En revanche, le péché populaire / extrait fract a des lignes assez diagonale prononcée sur mon GPU étant donné les mêmes entrées.

Un inconvénient est qu'il nécessite v3.30 GLSL. Et bien qu'il semble assez vite, je ne l'ai pas empiriquement quantifié ses performances. Shader Analyseur d'AMD prétend 13,33 pixels par cycle d'horloge pour la version vec2 sur une HD5870. Contraste avec 16 pixels par cycle d'horloge pour le sin / extrait fract. Il est donc certainement un peu plus lent.

Voici ma mise en œuvre. Je l'ai laissé dans diverses permutations de l'idée de le rendre plus facile à tirer vos propres fonctions de.

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

Sortie de aléatoire (vec3) dans static.frag

Je visitai 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 la distribution est uniforme et couvre la plage attendue.

Bruit d'or

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

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 le bruit d'or dans votre navigateur en ce moment!

Cette fonction a une meilleure répartition aléatoire sur la fonction en cours dans la réponse de @appas au 9 septembre 2017:

La fonction @appas est également incomplète, étant donné qu'il n'y a pas fourni la semence (uv n'est pas une graine - même pour chaque image), et ne fonctionne pas avec les chipsets bas de précision. Le bruit court or à faible précision par défaut (beaucoup plus rapide).

Il y a aussi une belle mise en œuvre décrit ici par McEwan et @StefanGustavson qui ressemble à un bruit de Perlin, mais « ne nécessite aucune configuration, à savoir pas textures ni tableaux uniformes. il suffit de l'ajouter à votre code source de shaders et appeler où vous voulez ».

C'est très pratique, surtout étant donné que la mise en œuvre antérieure de Gustavson, qui @dep liée à, utilise une texture 1D, qui est pas pris en charge dans GLSL ES (la langue des shaders de WebGL).

Je viens 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

Une version droite, dentelée 1d Perlin, essentiellement 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 bruit Perlin sur le propriétaire de shadertoy Inigo Quilez Perlin site web tutoriel et voronoi et ainsi de suite, il a des implémentations complètes et rapides codes pour eux.

hachage: De nos jours, il est donc webGL2.0 entiers sont disponibles dans (w) GLSL. -> pour hachage portable de qualité (à un coût similaire que hash flotteur laid), nous pouvons maintenant utiliser des techniques de hachage « graves ». QI mis en œuvre dans certains 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));
}

N'utilisez ceci:

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

Ne pas utiliser ceci:

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

Vous pouvez trouver l'explication dans améliorations apportées à l'GLSL one-liner canonique rand () pour OpenGL ES 2.0

S'il vous plaît voir ci-dessous un exemple comment ajouter du bruit blanc à la texture rendu. La solution est d'utiliser deux textures: original et le bruit blanc pur, comme celui-ci: wiki bruit blanc

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 contient le paramètre partagé uNoiseFactor qui est mis à jour à chaque rendu par l'application principale:

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

J'ai traduit l'une des implémentations Java de Ken Perlin dans GLSL et utilisé dans un couple sur des projets ShaderToy.

Voici l'interprétation GLSL je l'ai fait:

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

je l'ai traduit de l'Annexe B du chapitre 2 du matériel de bruit de Ken Perlin à cette source:

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

Voici une nuance publique, je l'ai fait sur Shader Toy qui utilise la fonction de bruit affiché:

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

D'autres bonnes sources que j'ai trouvé sur le sujet du bruit au cours de mes recherches comprennent:

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

Je recommande fortement le livre de shaders car il fournit non seulement une grande explication interactive du bruit, mais d'autres concepts de shaders ainsi.

EDIT:

Peut-être en mesure d'optimiser le code traduit en utilisant certaines des fonctions accélération matérielle disponibles en GLSL. Mettra à jour ce post si je finis par le faire.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top