Contents

利用shader生成随机数

本片文章主要讲述如何利用shader生成随机数。

一维随机

https://img-blog.csdnimg.cn/20200217102212402.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIzMDMwODQz,size_16,color_FFFFFF,t_70 y = fract(sin(x)*1.0); 上面的例子中,我们提取了sin函数其波形的分数部分.我们可以用这种效果通过把正弦函数打散成小片段来得到一些伪随机数如何实现呢?通过在sin(x)的值上乘以大些的数。 https://img-blog.csdnimg.cn/20200217102220535.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIzMDMwODQz,size_16,color_FFFFFF,t_70 y = fract(sin(x)*10.240);

https://img-blog.csdnimg.cn/20200217102226747.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIzMDMwODQz,size_16,color_FFFFFF,t_70 y = fract(sin(x)*100.0);

https://img-blog.csdnimg.cn/20200217102232960.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIzMDMwODQz,size_16,color_FFFFFF,t_70 y = fract(sin(x)*1000.0);

https://img-blog.csdnimg.cn/20200217102246244.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIzMDMwODQz,size_16,color_FFFFFF,t_70 y = fract(sin(x)*10000.0);

当我们不断的进行增大时,其实我们增大的是sin函数的幅度,但是由于fract的限制,这其实是增加fract的定义域,它会形成-1——1之间的更加密集的点。 细看,你可以看到 sin() 在 -1.5707 和 1.5707 上有较大波动——那就是sin取得最大值和最小值的地方。并且我们的中部更加的集中。

我们当然可以使用一些其他的变化

1
2
3
4
y = rand(x);
y = rand(x)*rand(x);
y = sqrt(rand(x));
y = pow(rand(x),5.);

这些都是伪随机,也就是说给定特定的数,生成的是特定的随机。

二维随机

我们要进行二维随机,其实就是能够把两个轴分开来看待。 https://img-blog.csdnimg.cn/20200217102253984.png

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

float random (vec2 st) {
    return fract(sin(dot(st.xy,
                         vec2(12.9898,78.233)))*
        43758.5453123);
}

void main() {
    vec2 st = gl_FragCoord.xy/u_resolution.xy;

    float rnd = random( st );

    gl_FragColor = vec4(vec3(rnd),1.0);
}

这里的dot可以根据不同的值位置,返回一个 0.0 到 1.0 之间的值。非常有用。 值得深思的问题是dot的值应该怎么取。首先必须要够大,很小的化,会拉低fract定义域。

我们根据得到坐标的整数部分作为一个通用值来隔离一个区域的像素,让它看起来像个单独的单元。然后我们可以用这个通用值来为这个区域得到一个随机值。因为我们的随机函数是伪随机,在那个单元内的所有像素返回的随机值都是一个常量。 https://img-blog.csdnimg.cn/20200217102301403.png

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

float random (vec2 st) {
    return fract(sin(dot(st.xy,
                         vec2(12.9898,78.233)))*
        43758.5453123);
}

void main() {
    vec2 st = gl_FragCoord.xy/u_resolution.xy;

    st *= 10.0; // Scale the coordinate system by 10
    vec2 ipos = floor(st);  // get the integer coords
    vec2 fpos = fract(st);  // get the fractional coords

    // Assign a random value based on the integer coord
    vec3 color = vec3(random( ipos ));

    // Uncomment to see the subdivided grid
    // color = vec3(fpos,0.0);

    gl_FragColor = vec4(color,1.0);
}

结合这两个量 — 坐标的整数部分和小数部分 — 将使你可以结合变化和秩序。