#### Discover more from GM Shaders Mini Tuts

# GM Shaders Mini: Noise

Hello people,

Today we're going to go over some common noise functions. These are useful all kinds of effects, like smoke, water, fire, clouds, terrain and so much more.

Tutorial Difficulty: **Intermediate**

## Hash Function

A hash function takes an input and returns a scrambled, pseudo-random output.

Let's say we have a float input "p" and we want a random float output between 0 and 1.

Most people use a sine-wave multiplied by a huge number and use the fractional part of that to get a "random" number between 0 and 1:

`return`

` fract(sin(p * 0.129898) * 43758.5453);`

This is a 1D hash function because it has a single float input. The numbers here aren't too important as long as doesn't produce any obvious patterns.

This is much more useful with a vec2 input though:

`return`

` fract(sin(p.x*0.129898 + p.y*0.78233) * 43758.5453);`

It's essentially the same process, but we add each component with a different, random multiplier. You want to make sure the two numbers aren't obvious ratios like 1 to 2 because then you'll get obvious patterns. That's why we include random fractions.

Here's an illustration:

On the left side, we're using simplified multipliers:

`... p.x*0.12 + p.y*0.78 ...`

So choose your "magic numbers" carefully! You don't have to do a lot of math, just play around until you find something that looks good.

Another trick I've learned

This is the baseline that all the other noise algorithms will use:

`float `

`hash1(`

`vec2 `

```
p)
{
```

`return fract`

`(`

`sin`

```
(p.x*0.129898 + p.y*0.78233) * 43758.5453);
}
```

I'm calling this "hash1" because there's just one float output.

## Value Noise

The principle of value noise is simple: It's a low-resolution version of the hash function, with interpolation. So we need to divide the coordinates into cells, get the hash at the corners of each cell, and smoothly interpolate between them.

Let's break it down into steps:

**Step 1: Round**

Round down the input coordinates to cells:

`vec2`

` cell = `

`floor`

`(p);`

This means each cell is 1 unit wide. This makes the math easier.

If you want it to be 64 pixels, then p should be the pixel coordinates divided by 64.

**Step 2: Sample corners**

Sample the 4 corners of each cell so that you can interpolate. Something like this:

`const`

` `

`vec2`

` off = `

`vec2`

```
(0,1);
```

`float `

```
hash_corner00 = hash1(cell + off.xx);
```

`float `

```
hash_corner10 = hash1(cell + off.yx);
```

`float `

```
hash_corner01 = hash1(cell + off.xy);
```

`float `

`hash_corner11 = hash1(cell + off.yy);`

**Step 3: Interpolate**

Next, we should interpolate between cell corners.

It will be easier to understand if you read the interpolation tutorial (or at least the "Cubic Filtering" section).

So first we need the sub-cell coordinates (fractional coordinates in each cell):

`vec2 `

`sub = p - cell;`

Then we can apply the cubic interpolation formula (optional):

`vec2 `

`cube = sub*sub*(3.-2.*sub);`

Next, we interpolate horizontally (top-left to top-right and bottom-left to bottom-right):

`float `

`hor0 = `

`mix`

```
(hash_corner00, hash_corner10, sub.x);
```

`float `

`hor1 = `

`mix`

`(hash_corner01, hash_corner11, sub.x);`

And finally, we can interpolate vertically to get the final result:

`return mix`

`(hor0, hor1, sub.y);`

A full code example will be linked at the end.

This can be extended to higher dimensions, but it gets exponentially more expensive. In 3D, you need to sample 8 corners of each cell and interpolate horizontally 4 times, vertically 2 times, and depthwise once. I'll leave that for you to research if you'd like!

## Perlin Noise

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 to 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:

## Conclusion

That seems like a good place to wrap up for today. I was planning to include Worley, Voronoi, and fractal noise, but that would probably make this a full tutorial instead of a mini!

I'll continue off here next week with the other noise functions, but in the meantime, you can check out my full ShaderToy example here!

Thanks for reading. Talk to ya next week!