Pregunta

A medida que la GPU proveedores de controladores por lo general no se molestan en poner en práctica noiseX en GLSL, estoy buscando un "gráficos aleatorización navaja suiza" conjunto de funciones de utilidad, preferentemente optimizado para su uso dentro de los sombreadores de GPU . Yo prefiero GLSL, pero el código cualquier idioma va a hacer por mí, estoy bien con la traducción por mi cuenta a GLSL.

En concreto, esperaría:

a) funciones pseudo-aleatoria - N-dimensional, la distribución uniforme en [-1,1] o sobre [0,1], calculado a partir de semillas M-dimensional (siendo idealmente cualquier valor, pero yo estoy bien con tener la semilla restringido a, por ejemplo, 0..1 para la distribución uniforme de resultados). Algo así como:

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) ruido continuo como Perlin Noise - de nuevo, N-dimensional, + - distribución uniforme, con un conjunto restringido de los valores y, así, en buen estado (algunas opciones para configurar la apariencia de los niveles de Perlin podría ser útil también). Yo esperaría firmas como:

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

No estoy mucho en la teoría de generación de números aleatorios, por lo que había más ansiosamente a dar un solución de pre-hechos , pero yo también aprecio respuestas como ", una de aquí muy bueno, rand 1D eficiente (), y deja que te explique cómo hacer un buen N-dimensional rand () en la parte superior de la misma ... ".

¿Fue útil?

Solución

Por muy simple cosas pseudo-mirando, yo uso esta oneliner que he encontrado en algún lugar de la Internet:

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

También puede generar una textura de ruido utilizando cualquier PRNG se quiere, a continuación, cargar esto en la manera normal y muestra los valores en su shader; Puedo desenterrar un ejemplo de código más tarde si lo desea.

Además, echa un vistazo a este archivo para implementaciones GLSL de Perlin y Simplex ruido , de Stefan Gustavson.

Otros consejos

  

aplicación de Gustavson utiliza una textura 1D

No, no, no desde el año 2005. Es que la gente insiste en la descarga de la versión antigua. La versión que se encuentra en el enlace que suministra usos única de 8 bits en 2D texturas.

La nueva versión de Ian McEwan de Ashima y yo no utiliza una textura, pero se ejecuta en alrededor de la mitad de la velocidad en las plataformas de escritorio típico con una gran cantidad de ancho de banda textura. En las plataformas móviles, la versión sin textura podría ser más rápido porque texturizado es a menudo un importante cuello de botella.

Nuestro repositorio de código fuente mantenido activa es:

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

Una colección tanto de la textureless y versiones textura que utilizan de ruido está aquí (usando sólo 2D texturas):

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

Si usted tiene alguna pregunta específica, no dude en enviarme un correo electrónico directamente (mi dirección de correo electrónico se puede encontrar en las fuentes classicnoise*.glsl.)

Se me ocurre que se puede utilizar una función de hash entero sencilla e insertar el resultado en mantisa de un flotador. IIRC garantiza la GLSL especificación de 32 bits enteros sin signo y representación flotante IEEE binary32 lo que debe ser perfectamente portátil.

Me dio a este un intento en este momento. Los resultados son muy buenos: se ve exactamente como estático con cada entrada he intentado, no hay patrones visibles en absoluto. En contraste, el pecado populares / fragmento bastante fract ha pronunciado líneas diagonales en mi GPU dadas las mismas entradas.

Una desventaja es que requiere v3.30 GLSL. Y aunque parezca lo suficientemente rápido, no he cuantificado empíricamente su rendimiento. Shader Analizador de AMD afirma 13.33 píxeles por ciclo de reloj para la versión vec2 en una HD5870. Contraste con 16 píxeles por reloj para el sen / fragmento fract. Así que sin duda es un poco más lento.

Aquí está mi aplicación. Lo dejé en varias permutaciones de la idea de hacer que sea más fácil para derivar sus propias funciones 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 );
}

Captura:

Salida de azar (vec3) en static.frag

Me inspeccionó la captura de pantalla en un programa de edición de imágenes. Hay 256 colores y el valor promedio es de 127, lo que significa la distribución es uniforme y cubre el rango esperado.

Oro ruido

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

Ver Oro de ruido en su navegador en este momento!

introducir descripción de la imagen aquí

Esta función tiene una mejor distribución aleatoria sobre la función actual en respuesta @appas' como de 09 de septiembre 2017:

introducir descripción de la imagen aquí

La función @appas también es incompleta, dado que no hay semillas suministrado (UV no es una semilla - el mismo para cada trama), y no funciona con conjuntos de chips de baja precisión. carreras de ruido de oro a la baja precisión por defecto (mucho más rápido).

También hay una buena implementación descrita aquí por McEwan y @StefanGustavson que se parece a Perlin ruido, pero "no requiere ningún tipo de configuración, es decir, no texturas ni matrices uniformes. Sólo tiene que añadir a su código fuente shader y llamar siempre que lo desee".

Esto es muy útil, especialmente teniendo en cuenta que la aplicación anterior de Gustavson, que @dep vinculada a, usa una textura 1D, que es no admitido en GLSL ES (el lenguaje de sombreado de WebGL).

Sólo encontraron esta versión de ruido 3D para la GPU, alledgedly es el más rápido 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

A recta, versión dentado de 1d Perlin, esencialmente un zigzag LFO aleatorio.

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

También he encontrado ruido Perlin 1-2-3-4d el propietario shadertoy inigo quilez perlin tutorial sitio web, y de Voronoi y así sucesivamente, tiene implementaciones rápidas completos y códigos para ellos.

de hash: Hoy en día hay tan webGL2.0 enteros están disponibles en GLSL (w). -> Hash portátil de calidad (a un costo similar al de los hashes de flotación feos) que ahora podemos utilizar técnicas de "graves" hash. IQ implementado algunos en https://www.shadertoy.com/view/XlXcW4 (y más )

por ejemplo:.

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

que usan esta corriente:

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

No utilice esto:

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

Se puede encontrar la explicación en Mejoras a la canónica de una sola línea rand GLSL () para OpenGL ES 2.0

Por favor, ver más abajo un ejemplo de cómo añadir ruido blanco para la textura prestado. La solución es utilizar dos texturas: ruido blanco original y pura, como éste: wiki ruido blanco

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

El fragmento compartido contiene parámetro uNoiseFactor que se actualiza en cada representación por aplicación principal:

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

He traducido una de las implementaciones de Java de Ken Perlin en GLSL y lo usó en un par de proyectos en ShaderToy.

A continuación se muestra la interpretación GLSL que hice:

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

Lo traduje del Apéndice B del Capítulo 2 de hardware ruido de Ken Perlin en esta fuente:

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

Aquí es un tono pública que hice en Shader juguete que utiliza la función de ruido de publicación:

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

Algunas otras fuentes buenas que he encontrado sobre el tema del ruido durante mi investigación incluyen:

https://thebookofshaders.com/11/

https://mzucker.github.io/html/perlin -ruido-matemáticas-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

le recomiendo el libro de shaders ya que no sólo ofrece una gran explicación interactiva de ruido, pero otros conceptos de sombreado también.

EDIT:

podría ser capaz de optimizar el código traducido mediante el uso de algunas de las funciones de aceleración de hardware disponibles en GLSL. Se actualizará este post si termino haciendo esto.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top