Credits

Since giving credits is more important than anything else, I will do that first. This article is partially based on  two papers: A Survey of Procedural Noise Functions by A. Lagae et al and Efficient Computational Noise in GLSL by McEwan et al. Codes are sto-, ahem, taken from this gist and the table at the beginning of the post is taken from this article. Quotes from the papers are in blue, and are attributed using footnotes. The cover photo is taken directly from A Survey et al.

What is Perlin Noise?

Perlin Noise was created by Ken Perlin (who won the Academy Award for his achievement) in 1983. See, back then, photorealism was something to be desired by everyone, but people always came up short. Ken Perlin came up with his noise algorithm to battle this wretched “computer-looking” appearance of 3D models. Noise is the random number generator of computer graphics. It is a random and unstructured pattern, and is useful wherever there is a need for a source of extensive detail that is nevertheless lacking in evident structure.1 Perlin noise is a multi-dimensional algorithm used in procedural generation, textures, terrain generation, map generation, surface generation, vertex generation, and so on and so forth. The following table 2 shows the extent of Perlin noise:

Dimension Raw Noise (Grayscale) Uses
1

Things such as vectors which look hand-drawn

2

Things such as procedural textures, comme feu

3

Minecraft terrain uses Perlin Noise

Perlin gave the following definition for noise: “..noise is an approximation to white noise band-limited to a single octave.3 The formal definition of the noise is:

f_N(y_1, y_2, \cdots, y_n; x_1, x_2, \cdots, x_n) = P(N(x_1), N(x_2), \cdots, N(x_n))

Where N(x) is the noise function. Perlin noise is a procedural noise.The adjective procedural is used in computer science to distinguish entities that are described by program code rather than by data structures. 4 Meaning, something that is generated, not something that is hard-coded. What’s good about using a procedural noise, rather than say, creating the noise ourselves? Well, a procedural noise is compact, meaning it occupies less space. It’s continuous, meaning it’s non-periodic. It’s parametrized, it’s randomly accessible, and many other goodies that make the job of an artist easier… And isn’t that our end goal? To serve the artist? Yesterday, I made an After Effects plugin, which you can see it below this post. I didn’t have the artist in mind, I had my own ego and id in mind, so nobody downloaded it. I learned my lesson: Serve the artist, not yourself. Anyways…

 

Before Perlin, came Lattice gradient noises. They are geenrated by interpolating between random values, and Perlin noise uses a Cubic Lattice on each vertex and then doing a splined interpolation. The pseudo-random gradient is given by hashing the lattice point and using the result to choose a gradient. 5 These hashes are turned into 12 vectors, and they are interpolated from center to edge using a quintic polynomial. A little difficult to imagine right? No worries. We’ll provide pictures6 and pseudo-codes 7.

“… they are interpolated from center to edge using a quintic polynomial. “

And a pseudo-code for Classic Perlin, sans the hash function:

 

// Function to linearly interpolate between a0 and a1
// Weight w should be in the range [0.0, 1.0]
float lerp(float a0, float a1, float w) {
    return (1.0 - w)*a0 + w*a1;

    // as an alternative, this slightly faster equivalent formula can be used:
    // return a0 + w*(a1 - a0);
}

// Computes the dot product of the distance and gradient vectors.
float dotGridGradient(int ix, int iy, float x, float y) {

    // Precomputed (or otherwise) gradient vectors at each grid node
    extern float Gradient[IYMAX][IXMAX][2];

    // Compute the distance vector
    float dx = x - (float)ix;
    float dy = y - (float)iy;

    // Compute the dot-product
    return (dx*Gradient[iy][ix][0] + dy*Gradient[iy][ix][1]);
}

// Compute Perlin noise at coordinates x, y
float perlin(float x, float y) {

    // Determine grid cell coordinates
    int x0 = int(x);
    int x1 = x0 + 1;
    int y0 = int(y);
    int y1 = y0 + 1;

    // Determine interpolation weights
    // Could also use higher order polynomial/s-curve here
    float sx = x - (float)x0;
    float sy = y - (float)y0;

    // Interpolate between grid point gradients
    float n0, n1, ix0, ix1, value;
    n0 = dotGridGradient(x0, y0, x, y);
    n1 = dotGridGradient(x1, y0, x, y);
    ix0 = lerp(n0, n1, sx);
    n0 = dotGridGradient(x0, y1, x, y);
    n1 = dotGridGradient(x1, y1, x, y);
    ix1 = lerp(n0, n1, sx);
    value = lerp(ix0, ix1, sy);

    return value;
}

It is worth knowing that “… All noise functions except Perlin noise and sparse convolution noise are approximately band-pass. Perlin noise is only weakly band-pass, which might lead to problems with aliasing and detail loss.” 8 Plus, Perlin noise does not have Gaussian Amplitude DistributionMeaning, the speckles of noise don’t scatter based on Gaussian function, which is outside the scope of this article. There are many things that Perlin fairs well at, but there are things which it performs weakly at. In the following table plate 9 you can witness for yourself

 


There are many things that Perlin fairs well at, but there are things which it performs weakly at.

Perlin Noise in Practice: GLSL Implementations

Well, I said I will talk about Perlin noise in GLSL, and now I’m going to do it.

You can use Perlin noise as a wave, as a diffuse color, as a diffuse material, as a flickering light, and as some speckles on your texture. I personally used it in this instance as a color fizzler.

 

As I’m writing this, I’m contemplating an After Effects plugin which adds Perlin Noise functionality.

The simplest Perlin Noise can be construed10 as:

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

float noise(vec2 p, float freq ){
	float unit = screenWidth/freq;
	vec2 ij = floor(p/unit);
	vec2 xy = mod(p,unit)/unit;
	//xy = 3.*xy*xy-2.*xy*xy*xy;
	xy = .5*(1.-cos(PI*xy));
	float a = rand((ij+vec2(0.,0.)));
	float b = rand((ij+vec2(1.,0.)));
	float c = rand((ij+vec2(0.,1.)));
	float d = rand((ij+vec2(1.,1.)));
	float x1 = mix(a, b, xy.x);
	float x2 = mix(c, d, xy.x);
	return mix(x1, x2, xy.y);
}

float pNoise(vec2 p, int res){
	float persistance = .5;
	float n = 0.;
	float normK = 0.;
	float f = 4.;
	float amp = 1.;
	int iCount = 0;
	for (int i = 0; i<50; i++){
		n+=amp*noise(p, f);
		f*=2.;
		normK+=amp;
		amp*=persistance;
		if (iCount == res) break;
		iCount++;
	}
	float nf = n/normK;
	return nf*nf*nf*nf;
}
#define M_PI 3.14159265358979323846

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

float perlin(vec2 p, float dim, float time) {
	vec2 pos = floor(p * dim);
	vec2 posx = pos + vec2(1.0, 0.0);
	vec2 posy = pos + vec2(0.0, 1.0);
	vec2 posxy = pos + vec2(1.0);
	
	float c = rand(pos, dim, time);
	float cx = rand(posx, dim, time);
	float cy = rand(posy, dim, time);
	float cxy = rand(posxy, dim, time);
	
	vec2 d = fract(p * dim);
	d = -0.5 * cos(d * M_PI) + 0.5;
	
	float ccx = mix(c, cx, d.x);
	float cycxy = mix(cy, cxy, d.x);
	float center = mix(ccx, cycxy, d.y);
	
	return center * 2.0 - 1.0;
}

// p must be normalized!
float perlin(vec2 p, float dim) {
	
	/*vec2 pos = floor(p * dim);
	vec2 posx = pos + vec2(1.0, 0.0);
	vec2 posy = pos + vec2(0.0, 1.0);
	vec2 posxy = pos + vec2(1.0);
	
	// For exclusively black/white noise
	/*float c = step(rand(pos, dim), 0.5);
	float cx = step(rand(posx, dim), 0.5);
	float cy = step(rand(posy, dim), 0.5);
	float cxy = step(rand(posxy, dim), 0.5);*/
	
	/*float c = rand(pos, dim);
	float cx = rand(posx, dim);
	float cy = rand(posy, dim);
	float cxy = rand(posxy, dim);
	
	vec2 d = fract(p * dim);
	d = -0.5 * cos(d * M_PI) + 0.5;
	
	float ccx = mix(c, cx, d.x);
	float cycxy = mix(cy, cxy, d.x);
	float center = mix(ccx, cycxy, d.y);
	
	return center * 2.0 - 1.0;*/
	return perlin(p, dim, 0.0);
}

That is, however, a version of Perlin which was reconstructed in 2002. Visit the Gist to see how to apply Classic Perlin Noise.

Well, that is it for today! Short post, I know, and it was lacking in original content, but I am running out of ideas as of now, because I haven’t read Real-Time Rendering yet. It’s a book that’s chuckfull of concepts and ideas for learning, and teaching. I love this damn book!

 

Another book I’m currently reading is Fundamentals of Computer Graphics. I got a little stuck reading about Implicit Curves, but I’m going to ask my cousin, who holds a PhD in mathematics, to help me with it. I hope he does, because he has the tendency to forgoe my requests of intellectual assistance. Dunno, really. Aren’t cousins supposed to help each other? I will write him a visualization app in a minute if he asks… Au fait.

 

Je vous s’exprime quelque chose. S’il vous plait, se introdure mon blog a votre amis, parce que je veux plus visitors, et je veux se attendre les plus gens. Si ils ne voudraient visiter mon blog, leur dit “C’est genial comme un reine qu’est virgo entacta et veut votre putain!”

Dammit, I suck at French, at least I didn’t use Google Translate. Chubak Out.

Reference

  • A Survey of Procedural Noise Functions, Computer Graphics Forum, Volume 29 (2010), Number 8, pp 2379-2600
  • Efficient Computational Noise, Journal of Graphics Tools Volume 16, No. 2: 85-94

So, I finally made an After Effects plugin, but I’m afraid it’s rather mundane and useless. In fact, it’s called Mundane and Useless, and you can find it in the list of plugins under Partly Shaderly. To install, just drop the files (all the files!) into your common files, or AE plugin folder.

You can download it from here.

What does it do? Well it’s rather mundane and useless (again). It creates a grid of n circles. Nothing else. When you reach above 50 you’ll see the effect.

Why am I sharing this, you may ask? People make thousands of crappy plugins everyday. The answer is vanity, my friend, vanity. I’m an attention whore and I love posting my useless plugin. Problemo, Officero?