1. 程式人生 > >噪聲筆記#1 隨機值和白噪聲

噪聲筆記#1 隨機值和白噪聲

噪聲其實就是程式中的一些隨機變數,所以想要生成噪聲就先要有一個能夠生成(偽)隨機數的方法

生成隨機數的一些方法

(1)HASH

hash函式是可以用來生成隨機數 而且很常用,他會根據輸入的種子數生成並返回對應的隨機數,在圖形學中,通常返回0-1


 常用HASH函式

·直接取餘法:f(x):= x mod maxM ; maxM一般是不太接近 2^t 的一個質數。

·乘法取整法:f(x):=trunc((x/maxX)*maxlongit) mod maxM,主要用於實數。

·平方取中法:f(x):=(x*x div 1000 ) mod 1000000); 平方後取中間的,每位包含資訊比較多


先來一個最簡單地函式,修改P值來觀察影象

y = fract(sin(x)*P)

P=10      隨機函式P10

P=100    隨機函式P100

P=100000 隨機函式P100000

可以看到P=100000時已經很難直接判斷每個x對應的y值了,通過fract函式不停的將數值打碎在[0,1]之間,就有了隨機值的感覺

基於這個可以延展至二維、三維向量。

float Hash (vec2 p) {
    return fract(sin(dot(p.xy,vec2(12.9898,78.233)))*43758.5453123);
}

vec3 hash( vec3 p )
{
    p = vec3( dot(p,vec3(127.1,311.7, 74.7)),
              dot(p,vec3(269.5,183.3,246.1)),
              dot(p,vec3(113.5,271.9,124.6)));

    return fract(sin(p)*43758.5453123);
}

通過點乘(dot)二、三維向量可以得到一個[0,1]的一維浮點值,這樣就把問題變成了根據一個種子求一個隨機值,也就是一維的求隨機值。

(2)其他隨機數生成方式(做個記號,以後再瞭解)

線性同餘發生器(LCG) :N(i) = (a*N(i-1)+c) % m

進位相乘法(Multiply With Carry MWC)

線性反饋移位暫存器法(Linear Feedback Shift Register,LFSR)

斐波那契LFSR(Fabonacci LFSR)

伽羅華LFSR(Galois LFSR)

Mersenne Twister(MT)


生成白噪聲

知道了怎麼得到隨機值,就等於知道了怎麼生成白噪聲,白噪聲其實就是在二維向量得到隨機值

白噪聲unity

下面是unityshader的程式碼

Shader "Custom/WhiteNoise2D" {
	Properties{
		_Scale("Scale",Range(10,500)) = 1
	}
	SubShader{
		Pass{
			CGPROGRAM
			#include "UnityCG.cginc"
			#pragma vertex vert
			#pragma fragment frag
			float _Scale;
			struct v2f {
				float4 pos:SV_POSITION;
				half2 uv:TEXCOORD1;
			};

			float WhiteNoise2D(float2 st) {
				return frac(sin(dot(st.xy,
				float2(12.9898, 78.233)))*
				43758.5453123);
			}

			v2f vert(appdata_base v) {
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.uv = v.texcoord;
				return o;
			}
			fixed4 frag(v2f i) :SV_Target{
				half2 uv = floor(i.uv*_Scale)/_Scale;
				float random = WhiteNoise2D(uv);
				return fixed4(random,random,random,1);
			}
			ENDCG
		}
	}
	FallBack "Diffuse"
}

用白噪聲做個螢幕效果

TVNoise

Shader "Custom/TVNoiseShader" {
	Properties{
		_MainTex("Base(RGB)",2D)="white"{}
		_Scale("Scale",Float) = 50
		_TimeRate("TimeRate", Float) = 0.5
		_Fade("Fade", Range(0, 1)) = 0.5
		_Fill("Fill",Range(0,1)) = 0.1

	}
	SubShader{
		Pass{
			CGPROGRAM
			#include "UnityCG.cginc"
			#pragma vertex vert 
			#pragma fragment frag
			sampler2D _MainTex;
			float4 _MainTex_TexelSize;// Vector4(1 / width, 1 / height, width, height)
			float _Scale;
			float _TimeRate;
			float _Fade;
			float _Fill;
			struct v2f {
				float4 pos:SV_POSITION;
				half2 uv:TEXCOORD0;
			};

			inline fixed hash(float p) {
				return frac(sin(p)*43758.5453123);
			}
			inline fixed hash3(float3 p)
			{
				float3  a = float3(dot(p, float3(127.1, 311.7, 74.7)),
					dot(p, float3(269.5, 183.3, 246.1)),
					dot(p, float3(113.5, 271.9, 124.6)));

				return hash(a.x);//這裡簡化 只算第一個了
			}
			v2f vert(appdata_img v) {
				v2f o;
				o.pos= UnityObjectToClipPos(v.vertex);
				o.uv = v.texcoord;
				return o;
			}
			fixed4 frag(v2f i) :SV_Target{

				//保證不會因為螢幕比例而產生拉伸
				half2 suv = i.uv*_MainTex_TexelSize.zw/100;
				fixed value = hash3(float3(floor(suv*_Scale),floor(_Time.y/_TimeRate)));
				fixed3 color = tex2D(_MainTex, i.uv.xy);
				fixed value2 = hash(i.uv.x);
				color = lerp(color,fixed3(value, value,value),_Fade*step(value2,_Fill));
				return fixed4(color, 1);
			}
			ENDCG
		}
	}
}

參考內容:https://thebookofshaders.com/10/?lan=ch

https://blog.csdn.net/yolon3000/article/details/75145035