Procedural textures in WebGL

Many useful procedural patterns are based on just a few standard functions, most notably various kinds of "noise" functions. These functions are not included in GLSL by default, but the lab page includes definitions of the following functions which you can use to create patterns.

If you want to see the GLSL code for these functions, you can look at the source code for the lab page. It's all there, but the code contains GLSL mixed with JavaScript and HTML, so it's not very readable. Plus, it's a lot of GLSL code. These functions are easy to use, but hard to create, and we don't expect you to understand how they were written. That, in fact, is the subject of an advanced course in year 5 of the MT programme.

Perlin Noise

float perlinnoise(vec2 st)
float perlinnoise(float s, float t)
float perlinnoise(vec3 xyz)
float perlinnoise(float x, float y, float z)
float perlinnoise(vec2 xy, float z)
float perlinnoise(vec4 xyzw)
float perlinnoise(float x, float y, float z, float w)

All these return one value (float), in the range -1 to +1. To rescale it to the range 0 to 1 for use as a color component, multiply it by 0.5 and add 0.5:

float n = 0.5 + 0.5*perlinnoise(st);
gl_FragColor = vec4(n, n, n, 1.0);

To make the details of the pattern smaller, scale the texture coordinates:

float n = 0.5 + 0.5*perlinnoise(10.0 * st);
gl_FragColor = vec4(n, n, n, 1.0);

To animate the pattern over time, add a third coordinate that depends on time:

float n = 0.5 + 0.5*perlinnoise(10.0 * st, time);
gl_FragColor = vec4(n, n, n, 1.0);

Worley Noise

float worleynoise1(vec2 st)
float worleynoise1(vec3 xyz)
float worleynoise1(vec2 xy, float z)
vec2 worleynoise2(vec2 st)
vec2 worleynoise2(vec3 xyz)
vec2 worleynoise2(vec2 xy, float z)

These return one or two values (float or vec2), in the range 0 to slightly above 1. The values are the distance to the center of the nearest "cell" and (if two values are returned) the second nearest cell.

A cell-like pattern of white blobs:

float d = worleynoise1(5.0 * st);
float n = 1.0 - d*d;
gl_FragColor = vec4(n, n, n, 1.0);

A flagstone-like pattern of tiles:

vec2 d = worleynoise2(5.0 * st);
float n = d.y - d.x;
gl_FragColor = vec4(n, n, n, 1.0);

Flow Noise

float flownoise(vec2 st, float rot, out vec2 g)
float flownoise(vec2 st, float rot)

The first version returns a noise value, much like 2-D Perlin noise, but the small local wiggles of noise can be rotated by an angle, which makes the pattern swirl. The version with the "out vec2" argument also returns the gradient (derivative) of the noise function.

Filtered thresholding

float filterstep(float a, float x)

This creates an anti-aliased threshold, a transition between black and white that is one pixel wide and has a smoother appearance than an all-or-nothing thresholding like an if-else clause or the built-in GLSL function step().

A circle with a nice looking edge:

float dx = st.s - 0.5;
float dy = st.t - 0.5;
float d = sqrt(dx*dx + dy*dy);
float n = filterstep(0.3, d);
gl_FragColor = vec4(n, n, n, 1.0);
A crisp Worley tile pattern:

vec2 d = worleynoise2(5.0 * st);
float e = d.y - d.x;
float n = filterstep(0.1, e);
gl_FragColor = vec4(n, n, n, 1.0);