噪聲筆記#6 分形布朗運動
阿新 • • 發佈:2018-12-06
分形布朗運動(Fractal Brownian Motion)也就是fbm,它不是噪聲,但是他可以讓噪聲有更多的細節。可以看成把不同比例位置的一張噪聲合併在一起。
// Properties const int octaves = 1; float lacunarity = 2.0; float gain = 0.5; // // Initial values float amplitude = 0.5; float frequency = 1.; // // Loop of octaves for (int i = 0; i < octaves; i++) { value += amplitude * noise(frequency*uv); frequency *= lacunarity; amplitude *= gain; }
這就是一種 fbm函式 前面講了可以吧fbm看成多張噪聲的疊加
amplitude表示每一次噪聲疊加的權值,frequency 則是疊加噪聲的比例
octaves是迴圈次數,可以看成疊加幾張噪聲
lacunarity和gain則是用於修改amplitude和frequency 的值,讓每次疊加的噪聲權值和大小都不同。
fbm噪聲
值噪聲+fbm
Shader "Custom/FBMValueNoise" { Properties{ _Scale("Scale",Range(4,20)) = 10 [Header(properties)] _Octaves("Octaves",Int) = 1 _Lacunarity("lacunarity",Float)=2 _Gain("gain",Float)=0.5 [Header(fbm init)] _Amplitude("amolitude",Float) = 0.5 _Frequency("frequency",Float) = 1.0 } SubShader{ Pass{ CGPROGRAM #include "UnityCG.cginc" #pragma vertex vert #pragma fragment frag float _Scale; int _Octaves; float _Lacunarity; float _Gain; float _Amplitude; float _Frequency; struct v2f { float4 pos:SV_POSITION; half2 uv:TEXCOORD0; }; v2f vert(appdata_base v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.uv = v.texcoord; return o; } float rand(float2 st) { return frac(sin(dot(st.xy, float2(12.9898, 78.233))) * 43758.5453123); } float mix(float a, float b, float t) { return b*t + a*(1 - t); } float ValueNoise(float2 uv) { float2 i = floor(uv); float2 f = frac(uv); float a = rand(i); float b = rand(i + float2(1, 0)); float c = rand(i + float2(0, 1)); float d = rand(i + float2(1, 1)); float2 u = f*f*(3.0 - 2.0*f); return mix(a, b, u.x) + (c - a)* u.y * (1.0 - u.x) + (d - b) * u.x * u.y; //return mix(mix(a, b, u.x), mix(c, d, u.x), u.y); } float fbm(float2 uv) { /*如果要多次使用,要把_Frequency和_Amplitude賦值給新的,不能直接用,因為這兩個是全域性的*/ float v; for (int i = 0; i < _Octaves; i++) { v += _Amplitude*ValueNoise(_Frequency*uv); _Frequency *= _Lacunarity; _Amplitude *= _Gain; } return v; } fixed4 frag(v2f i) :SV_Target{ half2 uv = i.uv * _Scale; float noise = fbm(uv); return fixed4(noise, noise, noise, 1); } ENDCG } } FallBack "Diffuse" }
perlin噪聲+fbm
simplex噪聲+fbm
其他的FBM函式
上面其中一種FBM方法,你還可以用其他的FBM,會有不同的效果
湍流
for (int i = 0; i < OCTAVES; i++) {
value += amplitude * abs(snoise(st));
st *= 2.;
amplitude *= .5;
}
這裡多了個絕對值的運算
山脊
n = abs(n); // create creases n = offset - n; // invert so creases are at top n = n * n; // sharpen creases
PS:湍流和山脊這兩張圖和我參考的文章生成的圖差別很大,可能是生成噪聲的方式不同,建議參考原文
域翹曲(Domain Warping)
我們還可以用噪聲來扭曲紋理座標,可以看Inigo Quiles的這篇文章
Shader "Custom/Domain Warping" {
Properties{
_Scale("Scale",Float) = 10
[Header(properties)]
_Octaves("Octaves",Int) = 1
_Lacunarity("lacunarity",Float) = 2
_Gain("gain",Float) = 0.5
[Header(fbm init)]
_Amplitude("amolitude",Float) = 0.5
_Frequency("frequency",Float) = 1.0
[Header(Color)]
_Color0("Color0",Color)= (0.101961, 0.619608, 0.666667)
_Color1("Color1",Color) = (0.666667, 0.666667, 0.498039)
_Color2("Color2",Color) = (0, 0, 0.164706)
_Color3("Color3",Color) = (0.666667, 1, 1)
}
SubShader{
Pass{
CGPROGRAM
#include "UnityCG.cginc"
#pragma vertex vert
#pragma fragment frag
float _Scale;
int _Octaves;
float _Lacunarity;
float _Gain;
float _Amplitude;
float _Frequency;
float3 _Color0;
float3 _Color1;
float3 _Color2;
float3 _Color3;
struct v2f {
float4 pos:SV_POSITION;
half2 uv:TEXCOORD0;
};
inline float mix(float a, float b, float t) {
return b*t + a*(1 - t);
}
inline float3 mix3(float3 a, float3 b, float t) {
return float3(mix(a.x, b.x, t), mix(a.y, b.y, t), mix(a.z, b.z, t));
}
//from:https://www.shadertoy.com/view/XdXGW8
float2 random(float2 x) {
float2 k = float2(0.3183099, 0.3678794);
x = x*k + k.yx;
return -1.0 + 2.0*frac(16.0 * k*frac(x.x*x.y*(x.x + x.y)));
}
float perlinNoise(float2 uv) {
float2 i = floor(uv);
float2 f = frac(uv);
//為了直觀 單獨計算四個值
float value0 = dot(random(i + float2(0, 0)), f - float2(0, 0));
float value1 = dot(random(i + float2(1, 0)), f - float2(1, 0));
float value2 = dot(random(i + float2(0, 1)), f - float2(0, 1));
float value3 = dot(random(i + float2(1, 1)), f - float2(1, 1));
float2 u = f*f*(3.0 - 2.0*f);
//插值
return mix(mix(value0, value1,u.x), mix(value2, value3, u.x), u.y);
}
float fbm(in float2 uv) {
float v;
float frequency = _Frequency;
float amplitude = _Amplitude;
for (int i = 0; i < _Octaves; i++) {
v += amplitude*perlinNoise(frequency*uv);
frequency *= _Lacunarity;
amplitude *= _Gain;
}
return v;
}
float3 dw(float2 uv) {
//新增的向量只是單純的偏移可以隨便改
//第一層扭曲
float2 q = float2(fbm(uv + float2(0.0, 0.0)),
fbm(uv + float2(5.2, 1.3)));
//第二層扭曲
float2 r = float2(fbm(uv + 4.0*q + float2(1.7, 9.2) + 0.23*_Time.y),
fbm(uv + 4.0*q + float2(8.3, 2.8) + 0.53*_Time.y));
//第三層扭曲
float f= fbm(uv+4*r);
//上色
//第三層
float3 color = mix3(_Color0,_Color1,
clamp((f*f)*4.0, 0.0, 1.0));
//第一層
color = mix3(color, _Color2,
clamp(length(q), 0.0, 1.0));
//第二層
color = mix3(color, _Color3,
clamp(length(r.x), 0.0, 1.0));
return color;
}
v2f vert(appdata_base v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord;
return o;
}
fixed4 frag(v2f i) :SV_Target{
float3 color = dw(i.uv*_Scale);
return fixed4(color, 1);
}
ENDCG
}
}
FallBack "Diffuse"
}