Random / noise functions for GLSL

0 votes
asked Nov 16, 2010 by kos

As the GPU driver vendors don't usually bother to implement noiseX in GLSL, I'm looking for a "graphics randomization swiss army knife" utility function set, preferably optimised to use within GPU shaders. I prefer GLSL, but code any language will do for me, I'm ok with translating it on my own to GLSL.

Specifically, I'd expect:

a) Pseudo-random functions - N-dimensional, uniform distribution over [-1,1] or over [0,1], calculated from M-dimensional seed (ideally being any value, but I'm OK with having the seed restrained to, say, 0..1 for uniform result distribution). Something like:

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) Continous noise like Perlin Noise - again, N-dimensional, +- uniform distribution, with constrained set of values and, well, looking good (some options to configure the appearance like Perlin levels could be useful too). I'd expect signatures like:

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

I'm not very much into random number generation theory, so I'd most eagerly go for a pre-made solution, but I'd also appreciate answers like "here's a very good, efficient 1D rand(), and let me explain you how to make a good N-dimensional rand() on top of it..." .

7 Answers

0 votes
answered Nov 25, 2010 by appas

For very simple pseudorandom-looking stuff, I use this oneliner that I found on the internet somewhere:

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

You can also generate a noise texture using whatever PRNG you like, then upload this in the normal fashion and sample the values in your shader; I can dig up a code sample later if you'd like.

Also, check out this file for GLSL implementations of Perlin and Simplex noise, by Stefan Gustavson.

0 votes
answered Nov 7, 2011 by larsh

There is also a nice implementation described here by McEwan and @StefanGustavson that looks like Perlin noise, but "does not require any setup, i.e. not textures nor uniform arrays. Just add it to your shader source code and call it wherever you want".

That's very handy, especially given that Gustavson's earlier implementation, which @dep linked to, uses a 1D texture, which is not supported in GLSL ES (the shader language of WebGL).

0 votes
answered Nov 22, 2012 by stefan-gustavson

Gustavson's implementation uses a 1D texture

No it doesn't, not since 2005. It's just that people insist on downloading the old version. The version that is on the link you supplied uses only 8-bit 2D textures.

The new version by Ian McEwan of Ashima and myself does not use a texture, but runs at around half the speed on typical desktop platforms with lots of texture bandwidth. On mobile platforms, the textureless version might be faster because texturing is often a significant bottleneck.

Our actively maintained source repository is:

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

A collection of both the textureless and texture-using versions of noise is here (using only 2D textures):

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

If you have any specific questions, feel free to e-mail me directly (my email address can be found in the classicnoise*.glsl sources.)

0 votes
answered Nov 4, 2013 by spatial

It occurs to me that you could use a simple integer hash function and insert the result into a float's mantissa. IIRC the GLSL spec guarantees 32-bit unsigned integers and IEEE binary32 float representation so it should be perfectly portable.

I gave this a try just now. The results are very good: it looks exactly like static with every input I tried, no visible patterns at all. In contrast the popular sin/fract snippet has fairly pronounced diagonal lines on my GPU given the same inputs.

One disadvantage is that it requires GLSL v3.30. And although it seems fast enough, I haven't empirically quantified its performance. AMD's Shader Analyzer claims 13.33 pixels per clock for the vec2 version on a HD5870. Contrast with 16 pixels per clock for the sin/fract snippet. So it is certainly a little slower.

Here's my implementation. I left it in various permutations of the idea to make it easier to derive your own functions from.

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

Screenshot:

Output of random(vec3) in static.frag

I inspected the screenshot in an image editing program. There are 256 colours and the average value is 127, meaning the distribution is uniform and covers the expected range.

0 votes
answered Nov 25, 2013 by comprehensible

A straight, jagged version of 1d Perlin, essentially a random lfo zigzag.

        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);
        }
0 votes
answered Nov 6, 2014 by comprehensible

Just found this version of 3d noise for GPU, alledgedly it is the fastest one available:

#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
0 votes
answered Nov 22, 2015 by dominic-cerisano

Gold Noise

// Gold Noise ©2017 dcerisano@standard3d.com 
//  - based on the golden ratio, PI, and the square root of two
//  - faster one-line fractal noise generator function
//  - improved random distribution
//  - works with all chipsets (including low precision)
//  - gpu-optimized floating point operations (faster than integer)
//  - does not contain any slow division or unsupported bitwise operations


// Use mediump or highp for improved random distribution.
// This line can be removed for low precision chipsets and older GL versions.
//
precision lowp float;


// Irrationals with precision shifting 
//
float PHI = 1.61803398874989484820459 * 00000.1; // Golden Ratio   
float PI  = 3.14159265358979323846264 * 00000.1; // PI
float SRT = 1.41421356237309504880169 * 10000.0; // Square Root of Two


// Gold Noise function
//
float gold_noise(in vec2 coordinate, in float seed)
{
    return fract(sin(dot(coordinate*seed, vec2(PHI, PI)))*SRT);
}

See Gold Noise in your browser right now!

This function has improved random distribution over the current function in @appas' answer as of Sept 9, 2017:

enter image description here

The @appas function is also incomplete, given there is no seed supplied (uv is not a seed - same for every frame), and does not work with low precision chipsets. Gold Noise runs at low precision by default (much faster).

Welcome to Q&A, where you can ask questions and receive answers from other members of the community.
Website Online Counter

...