【零基础】充分理解WebGL(九)

avatar
掘金前首席打杂官

接上篇 juejin.cn/post/711642…

网格噪声

网格噪声(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;
}

code.juejin.cn/pen/7119301…

上面的代码绘制了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;
}

code.juejin.cn/pen/7119302…

我们最终得到的效果是界限分明的随机黑白网格。接下来我们用数学技巧来抹平边界,其实也不复杂,我们可以计算每个网格到周围八个网格的随机点的距离,取其中最近的距离作为距离场的值。

如果大家还记得上一讲介绍的二维噪声,会发现这个方法和二维噪声的原理很像,都是利用随机的二维距离场,也正因为如此这种技术才被叫做网格噪声。

#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;
}

code.juejin.cn/pen/7119305…

接下来,我们增加一些细节,把动态点显示出来,且增加时间变化,就可以得到下面的效果:

#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;
}

code.juejin.cn/pen/7119307…

网格噪声的思路还可以用来实现更有趣的例子,在Patricio Gonzalez Vivo创作的《the Book of Shaders》中专门用了一个章节来描述,有兴趣的同学可以阅读相关章节了解详细内容。

参考资料:thebookofshaders.com/12/?lan=ch