噪聲筆記#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
P=100
P=100000
可以看到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)
生成白噪聲
知道了怎麼得到隨機值,就等於知道了怎麼生成白噪聲,白噪聲其實就是在二維向量得到隨機值
下面是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"
}
用白噪聲做個螢幕效果
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
}
}
}