156 votos

Aleatorio / funciones de ruido para GLSL

Como el driver de la GPU de los proveedores no suelen molestar a implementar noiseX en GLSL, estoy en busca de una "gráfica de la aleatorización navaja suiza" función de utilidad de establecer, preferentemente optimizado para su uso dentro de GPU, shaders. Yo prefiero GLSL, pero el código de cualquier idioma va a hacer por mí, yo estoy bien con la traducción en mis el propios para GLSL.

Específicamente, me gustaría esperar:

a) Pseudo-funciones aleatorias N-dimensionales, de distribución uniforme sobre [-1,1] o [0,1], calculada a partir de M-dimensional de la semilla (idealmente ser cualquier valor, pero yo estoy bien con el hecho de tener la semilla restringido a, digamos, 0..1 para uniformes de distribución de resultados). Algo 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) Continuo ruido como el Ruido Perlin - de nuevo, la N-dimensional, +- distribución uniforme, con limitados conjunto de valores y, así, en buen estado (algunas de las opciones para configurar la apariencia como Perlin niveles podría ser útil también). Yo esperaría que firmas como:

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

No estoy muy en la generación de números aleatorios de la teoría, así que me gustaría más ansiosamente ir para un pre-solución, pero también me gustaría apreciar respuestas como "aquí hay una muy buena, eficiente 1D rand(), y me explico cómo hacer un buen N-dimensional rand() en la parte superior de la misma..." .

241voto

dep Puntos 1636

Por muy simple pseudoaleatoria-mirando cosas, yo uso esta oneliner que he encontrado en internet en algún lugar:

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, con independencia de los PRNG te gusta, a continuación, cargar esto en el modo normal, y muestra los valores en el sombreado; puedo desenterrar un ejemplo de código más tarde si quieres.

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

69voto

Stefan Gustavson Puntos 399

Gustavson la aplicación utiliza una textura 1D

No, no, no desde el 2005. Es simplemente que la gente insista en la descarga de la versión anterior. La versión que está en el enlace que suministra sólo utiliza 8 bits texturas 2D.

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

Nuestros mantiene activa del repositorio de origen es:

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

Una colección de los sin texturas y textura-el uso de versiones de ruido está aquí (usando solo texturas 2D):

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

Si usted tiene alguna pregunta, siéntase libre de enviarme un correo electrónico directamente a mi dirección de correo electrónico se pueden encontrar en la classicnoise*.glsl fuentes.)

65voto

Spatial Puntos 181

Se me ocurre que se podría utilizar un entero simple función de hash y de insertar el resultado en una carroza de la mantisa. Si mal no recuerdo el GLSL especificación de las garantías de 32 bits sin signo enteros y IEEE binary32 float representación de lo que debe ser perfectamente portátil.

Esto dio una oportunidad ahora. Los resultados son muy buenos: se ve exactamente como estático con cada entrada he intentado, y no se observan patrones. En contraste, el pecado popular/fract fragmento tiene bastante pronunciada líneas diagonales en mi GPU dado a las mismas entradas.

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

Aquí está mi aplicación. He dejado en varias permutaciones de la idea para hacer más fácil para derivar sus propias funciones.

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

Output of random(vec3) in static.frag

He inspeccionado la captura de pantalla en un programa de edición de imágenes. Hay 256 colores y el valor promedio es de 127, es decir, la distribución es uniforme y cubre el rango esperado.

11voto

LarsH Puntos 14726

También hay una buena implementación se describe aquí por McEwan y @StefanGustavson que parece ruido Perlin, pero "no requiere ningún tipo de instalación, es decir, no se texturas ni uniforme matrices. Acaba de añadir a su shader código fuente y llame a donde tú quieras".

Eso es muy útil, especialmente teniendo en cuenta que Gustavson anterior de la aplicación, que dep @vinculado, utiliza una 1D textura, que no se admite en GLSL ES (el lenguaje de sombreado de WebGL).

9voto

user2150119 Puntos 71

Tenga en cuenta que cualquier cosa usando funciones trigonométricas en GLSL ha indefinido de precisión. Tengo problemas con un generador de números aleatorios, dependiendo sin(), no generan los mismos resultados de ATI y NVIDIA. El aceptó respuesta aquí puede mostrar el mismo problema, pero no lo he confirmado.

Gustavson la solución no parece que el uso de cualquier función con la undefined precisión, por lo que probablemente debería estar bien para usar mientras espera que aproximadamente el mismo resultado en diferentes plataformas.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X