The Book of Shaders - Generative designs - Noise[1] 学习笔记.
1. Random 2D
首先实现之前学过的的2D随机函数, 即输入一个2D坐标, 输出(0,1)随机值:
float random(in vec2 st)
{
return fract(sin(dot(st.xy,vec2(12.9898,78.233)))*43758.5453123);
}
在调用这个函数前, 用 floor 函数将坐标网格化:
void main()
{
vec2 st = gl_FragCoord.xy/u_resolution.xy;
vec2 pos = floor(st*10.0);
float n = random(pos);
gl_FragColor = vec4(vec3(n), 1.0);
}
效果如下:
2. Noise 2D
然后实现2D噪声函数, 方法是获取周围4个点的随机值, 然后根据当前坐标的小数部分(利用 fract 函数), 插值得到最终噪声值. 插值时用到了之前学的 SmoothStep 进行非线性插值.
如图所示, 四个角的高度表示它们的随机值, 分别为代码中的a, b, c, d. 非线性插值获得中间的高度, 即所求噪声值.
借用The Book of Shaders的插图:
代码如下:
float noise(in vec2 st)
{
vec2 i = floor(st);
vec2 f = fract(st);
float a = random(i);
float b = random(i + vec2(1.0, 0.0));
float c = random(i + vec2(0.0, 1.0));
float d = random(i + vec2(1.0, 1.0));
// smooth step
vec2 u = f*f*(3.0-2.0*f);
float ab = mix(a, b, u.x);
float cd = mix(c, d, u.x);
return mix(ab, cd, u.y);
// 功能与上面三行相同
// return mix(a, b, u.x) +
// (c - a)* u.y * (1.0 - u.x) +
// (d - b) * u.x * u.y;
}
在调用时, 直接传入坐标:
void main()
{
vec2 st = gl_FragCoord.xy/u_resolution.xy;
vec2 pos = st*10.0;
float n = noise(pos);
gl_FragColor = vec4(vec3(n), 1.0);
}
效果如下:
3. Fractal Noise 2D
之前用 Shadershop 实现了1D的分形噪声, 原理是将多个缩放程度不同的 Noise 叠加起来, 现在也用 Noise2D 来实现分形噪声.
void main()
{
vec2 st = gl_FragCoord.xy/u_resolution.xy;
float n = 0.0;
n += noise(st*10.0);
n += noise(st*20.0)/2.0;
n += noise(st*40.0)/4.0;
n += noise(st*80.0)/8.0;
n += noise(st*160.0)/16.0;
n += noise(st*320.0)/32.0;
// 限制值在[0,1]
n = n*0.5;
gl_FragColor = vec4(vec3(n), 1.0);
}
最终效果如下:
参考文献
[1] Patricio Gonzalez Vivo, Jen Lowe. The Book of Shaders. Retrieved Jan. 9, 2019, from https://thebookofshaders.com/11/?lan=ch