噪声其实就是程序中的一些随机变量,所以想要生成噪声就先要有一个能够生成(伪)随机数的方法
生成随机数的一些方法
(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
}
}
}