分形布朗运动(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 的值,让每次叠加的噪声权值和大小都不同。
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"
}
上面其中一种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:湍流和山脊这两张图和我参考的文章生成的图差别很大,可能是生成噪声的方式不同,建议参考原文
我们还可以用噪声来扭曲纹理坐标,可以看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"
}
参考内容:https://thebookofshaders.com/13/?lan=ch