网格噪声
网格噪声基于距离场,这里的距离是指到一个特征点集最近的点的距离。比如说我们要写一个 4 个特征点的距离场,我们应该做什么呢?对每一个像素,计算它到最近的特征点的距离。也就是说,我们需要遍历所有 4 个特征点,计算他们到当前像素点的距离,并把最近的那个距离存下来。
float min_dist = 100.; // A variable to store the closest distance to a point
min_dist = min(min_dist, distance(st, point_a));
min_dist = min(min_dist, distance(st, point_b));
min_dist = min(min_dist, distance(st, point_c));
min_dist = min(min_dist, distance(st, point_d));
![在这里插入图片描述](https://img-blog.csdnimg.cn/03d1292ae212434d8226ddf2f04fb05f.png#pic_center)
#ifdef GL_ES
precision mediump float;
#endif
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
void main() {
vec2 st = gl_FragCoord.xy/u_resolution.xy;
st.x *= u_resolution.x/u_resolution.y;
vec3 color = vec3(.0);
// Cell positions
vec2 point[5];
point[0] = vec2(0.83,0.75);
point[1] = vec2(0.60,0.07);
point[2] = vec2(0.28,0.64);
point[3] = vec2(0.31,0.26);
point[4] = u_mouse/u_resolution;
float m_dist = 1.; // minimum distance
// Iterate through the points positions
for (int i = 0; i < 5; i++) {
float dist = distance(st, point[i]);
// Keep the closer distance
m_dist = min(m_dist, dist);
}
// Draw the min distance (distance field)
color += m_dist;
// Show isolines
// color -= step(.7,abs(sin(50.0*m_dist)))*.3;
gl_FragColor = vec4(color,1.0);
}
平铺和迭代
把空间分割成网格。并不需要计算每一个像素点到每一个特征点的距离。每个像素点是在自己的线程中运行,我们可以把空间分割成网格(cells),每个网格对应一个特征点。另外,为避免网格交界区域的偏差,我们需要计算像素点到相邻网格中的特征点的距离。每个像素点只需要计算到九个特征点的距离:他所在的网格的特征点和相邻的八个网格的特征点。
// Scale
st *= 3.;
// Tile the space
vec2 i_st = floor(st);
vec2 f_st = fract(st);
![在这里插入图片描述](https://img-blog.csdnimg.cn/3adc5f25f8994defa72d9f45963eba90.png#pic_center) 我们将使用网格坐标(存储在整数坐标 i_st 中)来构造特征点的随机位置。random2f 函数接受一个 vec2 类型参数,返回给我们一个 vec2 类型的随机位置。所以,在每个网格内,我们有一个特征点在随机位置上。
vec2 point = random2(i_st);
网格内的每个像素点(存储在浮点坐标 f_st 中)都会计算它到那个随机点的距离。
vec2 diff = point - f_st;
float dist = length(diff);
我们还需要计算像素点到相邻网格中随机点的距离,而不只是当前的网格。我们需要 遍历 所有相邻网格。不是所有网格,仅仅是那些和当前网格相邻的网格。从网格坐标来说,就是 x 坐标从 -1 (左)到 1 (右), y 坐标从 -1 (下)到 1 (上)。一个 9 个网格的 3x3 区域可以用两个 for 循环遍历:
for (int y= -1; y <= 1; y++) {
for (int x= -1; x <= 1; x++) {
// Neighbor place in the grid
vec2 neighbor = vec2(float(x),float(y));
...
}
}
#ifdef GL_ES
precision mediump float;
#endif
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
vec2 random2( vec2 p ) {
return fract(sin(vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3))))*43758.5453);
}
void main() {
vec2 st = gl_FragCoord.xy/u_resolution.xy;
st.x *= u_resolution.x/u_resolution.y;
vec3 color = vec3(.0);
// Scale
st *= 3.;
// Tile the space
vec2 i_st = floor(st);
vec2 f_st = fract(st);
float m_dist = 1.; // minimum distance
for (int y= -1; y <= 1; y++) {
for (int x= -1; x <= 1; x++) {
// Neighbor place in the grid
vec2 neighbor = vec2(float(x),float(y));
// Random position from current + neighbor place in the grid
vec2 point = random2(i_st + neighbor);
// Animate the point
point = 0.5 + 0.5*sin(u_time + 6.2831*point);
// Vector between the pixel and the point
vec2 diff = neighbor + point - f_st;
// Distance to the point
float dist = length(diff);
// Keep the closer distance
m_dist = min(m_dist, dist);
}
}
// Draw the min distance (distance field)
color += m_dist;
// Draw cell center
color += 1.-step(.02, m_dist);
// Draw grid
color.r += step(.98, f_st.x) + step(.98, f_st.y);
// Show isolines
// color -= step(.7,abs(sin(27.0*m_dist)))*.5;
gl_FragColor = vec4(color,1.0);
}
这个算法也可以从特征点而非像素点的角度理解。在那种情况下,算法可以表述为:每个特征点向外扩张生长,直到它碰到其它扩张的区域。这反映了自然界的生长规则。生命的形态是由内部扩张、生长的力量和限制性的外部力量共同决定的。模拟这种行为的算法以 Georgy Voronoi 命名。