网格噪声
网格噪声(Cellular Noise)是一种现在被广泛使用的程序生成纹理技术,它的原理是将噪声和网格结合起来。
在前面的章节,我们已经多次运用过网格生成技术,它的原理也非常简单,就是通过坐标放大和取小数点的数学技巧来实现。在这里我们通过下面的例子复习一下:
#!/jcode/lang/glsl https://xitu.github.io/jcode-languages/dist/lang-glsl.json
#version 300 es
precision highp float;
uniform vec2 dd_resolution;
out vec4 FragColor;
void main() {
vec2 st = gl_FragCoord.xy / dd_resolution;
st *= 10.0;
st = fract(st);
FragColor.rgb = vec3(st.x, st.y, 1.0);
FragColor.a = 1.0;
}
上面的代码绘制了10x10的网格,如果我们在其中引入随机距离场:
#version 300 es
precision highp float;
vec2 random(vec2 st){
st = vec2( dot(st,vec2(127.1,311.7)),
dot(st,vec2(269.5,183.3)) );
return fract(sin(st) * 43758.5453123);
}
uniform vec2 dd_resolution;
out vec4 FragColor;
void main() {
vec2 st = gl_FragCoord.xy / dd_resolution;
st *= 10.0;
vec2 idx = floor(st);
vec2 pct = fract(st);
vec2 p = random(idx);
float d = distance(pct, p);
FragColor.rgb = vec3(d);
FragColor.a = 1.0;
}
我们最终得到的效果是界限分明的随机黑白网格。接下来我们用数学技巧来抹平边界,其实也不复杂,我们可以计算每个网格到周围八个网格的随机点的距离,取其中最近的距离作为距离场的值。
如果大家还记得上一讲介绍的二维噪声,会发现这个方法和二维噪声的原理很像,都是利用随机的二维距离场,也正因为如此这种技术才被叫做网格噪声。
#version 300 es
precision highp float;
vec2 random(vec2 st){
st = vec2( dot(st,vec2(127.1,311.7)),
dot(st,vec2(269.5,183.3)) );
return fract(sin(st) * 43758.5453123);
}
uniform vec2 dd_resolution;
out vec4 FragColor;
void main() {
vec2 st = gl_FragCoord.xy / dd_resolution;
st *= 10.0;
vec2 idx = floor(st);
vec2 pct = fract(st);
float d = 1.0;
for(int i = -1; i <= 1; i++) {
for(int j = -1; j <= 1; j++) {
vec2 neighbor = vec2(float(i), float(j));
vec2 p = random(idx + neighbor);
d = min(d, distance(pct, neighbor + p));
}
}
FragColor.rgb = vec3(d);
FragColor.a = 1.0;
}
接下来,我们增加一些细节,把动态点显示出来,且增加时间变化,就可以得到下面的效果:
#version 300 es
precision highp float;
vec2 random(vec2 st){
st = vec2( dot(st,vec2(127.1,311.7)),
dot(st,vec2(269.5,183.3)) );
return fract(sin(st) * 43758.5453123);
}
uniform vec2 dd_resolution;
uniform float dd_time;
out vec4 FragColor;
void main() {
vec2 st = gl_FragCoord.xy / dd_resolution;
st *= 10.0;
vec2 idx = floor(st);
vec2 pct = fract(st);
float d = 1.0;
for(int i = -1; i <= 1; i++) {
for(int j = -1; j <= 1; j++) {
vec2 neighbor = vec2(float(i), float(j));
vec2 p = random(idx + neighbor);
p = 0.5 + 0.5 * sin(dd_time + 6.2831 * p);
d = min(d, distance(pct, neighbor + p));
}
}
FragColor.rgb = vec3(d) + step(d, 0.03);
FragColor.a = 1.0;
}
网格噪声的思路还可以用来实现更有趣的例子,在Patricio Gonzalez Vivo创作的《the Book of Shaders》中专门用了一个章节来描述,有兴趣的同学可以阅读相关章节了解详细内容。