Noise Generation Algorithms : White Noise

January 14, 2018
10m
Unity 3DShadersAlgorithm

Many of you may know what white noise is and how it can be used in code.
But there are a spectrum of  'Colored Noises' as well these include ones like brown noise, pink, blue and violet noise all these have slightly different properties and can be very useful in creating different effects. More details on colored noises can be found HERE.

Comparison of noiseless and noisy image

A lot of movies as well as video games like City Skylines use white noise to add a feeling of realism and texture to the on screen content, it's also referred to as a grain filter or overlay. It is a really subtle effect and should not be over used.
Creating white noise boils down to the random function used.
While writing C++ code or C# code we have access to good pseudo-random functions from their standard libraries... but while writing code in shaders we usually have to create our own pseudo-random number generator.
One really good way of making one is by using the frac ( in Unity & HLSL ) or fract ( in GLSL ) function which returns the fractional part of a number.


float random( float2 point )
{
   return frac(sin(dot(point.xy,float2(someXvalue,someYvalue)))*someFloatWithManyDecimals);
}

Why are we using this 'special arrangement' of functions to make our pseudo-random number generator?
The dot product :- gives values based on how close the directions of  2 vectors are to each other.
The sin function :- gives us value from -1.0 to 1.0 based on the input from the dot product.
The frac function :- gives us the fractional part of the entire thing, which will be our random number.
After tweaking some of these values you should be getting a pretty decent random number generator.
We will be making an effect that looks like this. It's a bit exaggerated for effect.

An example of grain filter shader

First we will see what the properties of the shader are:


Properties
{
 _MainTex("Texture", 2D)="white"
 _NoiseScale("Noise Scale",Float) = 50.0
 _Strength("Noise Strength",Float) = 1.0
}

What are they? :


sampler2D _MainTex; //Texture Used
float _NoiseScale; //How big each noise block is
float _Strength; //How prevalent it is in final image

We will look at the random function used ( by me ).


float random( float2 p )
{
     return frac(sin(dot(p.xy ,float2( _Time.y,6.115)))*53.8856);
}

I have used _Time.y as a parameter to change the noise each frame.
Now the fragment shader:


fixed4 frag (v2f i) : SV_Target
{
 float2 normUV = i.uv; 
 normUV *= _NoiseScale; // Scale the coordinate system by _NoiseScale amount
 float2 ipos = floor(normUV);  // get the integer coords 
 float rand = random(ipos); // Assign a random value based on the integer coord
 fixed4 col = fixed4(rand,rand,rand,1.0);
 col = lerp( tex2D(_MainTex,i.uv),col,_Strength ); /*Interpolating between the noise and 
                                                          texture image by _Strength Value*/
 return col;
}

The entire source code:

Shader Lab

1Shader "BitShiftProductions/Noises"
2{
3	Properties
4	{
5		_MainTex("Texture", 2D)="white"
6		_NoiseScale("Noise Scale",Float) = 5.0
7		_Strength("Noise Strength",Float) = 1.0
8	}
9	SubShader
10	{
11		Tags { "RenderType"="Opaque" }
12
13		Pass
14		{
15			CGPROGRAM
16			#pragma vertex vert
17			#pragma fragment frag
18			
19			#include "UnityCG.cginc"
20
21			struct appdata
22			{
23				float4 vertex : POSITION;
24				float2 uv : TEXCOORD0;
25			};
26
27			struct v2f
28			{
29				float2 uv : TEXCOORD0;
30				float4 vertex : SV_POSITION;
31			};
32
33			sampler2D _MainTex;
34			float _NoiseScale;
35			float _Strength;
36			
37			v2f vert (appdata v)
38			{
39				v2f o;
40				o.vertex = UnityObjectToClipPos(v.vertex);
41				o.uv = v.uv;
42				return o;
43			}
44
45			float random( float2 p )
46			{
47				return frac(sin(dot(p.xy,float2(_Time.y,65.115)))*2773.8856);
48			}
49			fixed4 frag (v2f i) : SV_Target
50			{
51				float2 normUV = i.uv; 
52				normUV *= _NoiseScale; // Scale the coordinate system by 10
53			    float2 ipos = floor(normUV);  // get the integer coords
54
55			    // Assign a random value based on the integer coord
56			    float rand = random(ipos);
57			    fixed4 col = fixed4(rand,rand,rand,1.0);
58			    col = lerp( tex2D(_MainTex,i.uv),col,_Strength);
59			    return col;
60			}
61
62			ENDCG
63		}
64	}
65}