Perlin noise is quite similar to value noise, but instead of interpolating single hash values, it interpolates between gradients that go in random directions.

This can produce smoother, more natural-looking results, but at a higher performance cost.

Let’s go through the steps:

**Step 1: Vector Hash**

We need a vec2 hash instead of a single value:

**return fract**(**sin**(p * **mat2**(0.129898, 0.78233, 0.81314, 0.15926)) * 43758.5453);

I’m calling this function “hash2” because it returns a vec2 output. The mat2 here is a shorter way of writing:

`p.x * `**vec2**(0.129898, 0.81314) + p.y***vec2**(0.78233, 0.15926)

And to get a random unit vector:

**return normalize**(**hash2**(p) - 0.5);

I’m calling this “hash2_norm”. We’ll need both functions later.

**Step 2: Sample corners**

Just like with value noise, we divide into cells and sample direction vectors for the 4 corners:

**vec2 **dir_corner00 = hash2_norm(cell+off.xx);

**vec2 **dir_corner10 = hash2_norm(cell+off.yx);

**vec2 **dir_corner01 = hash2_norm(cell+off.xy);

**vec2 **dir_corner11 = hash2_norm(cell+off.yy);

But calculate the gradients, we need to compute the dot product of the direction and the difference between the sample point and the corner.

The dot product here just tells how far along the random axis, the current sample point is.

**float **grad_corner00 = **dot**(dir_corner00, off.xx-sub);

**float **grad_corner10 = **dot**(dir_corner10, off.yx-sub);

**float** grad_corner01 = **dot**(dir_corner01, off.xy-sub);

**float **grad_corner11 = **dot**(dir_corner11, off.yy-sub);

Don’t worry! This is the hardest part!

**Step 3: Interpolate**

The same process as with the value noise, but we’ll use “quintic” interpolation instead of cubic.

**vec2** quint = sub*sub*sub*(10.0 + sub*(-15.0 + 6.0*sub));

Feel free to compare to cubic and linear interpolation!

Now we interpolate:

**float **hor0 = **mix**(grad_corner00, grad_corner10, quint.x);

**float **hor1 = **mix**(grad_corner01, grad_corner11, quint.x);

**Note:** these values can range from -sqrt(2.0) to +sqrt(2.0), so to get a value between 0 and 1, I multiply by 0.7 (approximately sqrt(0.5)) and add 0.5.

**return mix**(hor0, hor1, quint.y) * 0.7 + 0.5;

And that’s it. You should get something like this: