随机和噪声

287 阅读3分钟

js随机数

js只要调用Math.random就能生成 0-1之间的随机数,虽然是伪随机,也够用了。

如果觉得不够也可以使用crypto,代码如下,返回结果同样是0-1。

真的伪随机

但是,glsl 中没有内置random函数,所以,要用的话,需要手写一个,也很简单。

float random (float x){ 
    return  fract(cos(x* 123.342)*43242.123213)  ; 
}

我们来大致分析一下, 最外层的fract保证了返回值的值域为0-1。而内部是一个余弦函数,不论是周期的放大,还是余弦值的放大都是为了增加随机性,增加值域的覆盖范围。

我们逐渐改变代码可以看到函数的曲线。

float random(float x){
    //  return  cos(x) ;
    //  return  fract(cos(x)) ;
    //  return  fract(cos(x* 123.342)) ;
     return  fract(cos(x* 123.342)*43242.123213) ;
}

image.png

image.png

image.png

image.png

这个函数是伪随机,很明显,只要传参确定返回值就确定。但是规律性一般也看不出来,所以用作随机数够了。

这个函数需要注意的是,系数的小数位是必要的。

二维

二维随机就是一个二元函数。 实现方式,可以直接套用一维随机,也可以用点乘,可以输出单个数,也可以输出二维向量。

 float random2d1(vec2 coord){
    return fract(sin(dot(coord.xy, vec2(12.9898, 78.233))) * 43758.5453);
}

vec2 random2d(vec2 st){ 
    return fract( sin( vec2 ( dot(st, vec2(1232.34545, 321.2312)), 
                                              dot(st, vec2(269.5, 183.23 ))  
    ))* 43758.4775 )  ; 
}

在glsl 中,使用随机通常都是和坐标关联。


    color= vec3(random2d(st), random(st.x) );
    gl_FragColor = vec4(color,1) ;

image.png

噪声

噪声和随机有什么区别呢?

区别大概就是,虽然是随机但不是那么的随机。 是不是像极了某某产品的经典需求。

像大海的波涛,沉积岩的纹理,树叶的脉络等等,都充满了随机(不可预测性)。伪随机是可以预测的,我们这里实际上还是伪随机。

但是我们只是想去模拟它。

一般的noise实现,会拆开一个数的整数和小数部分。 下面的图,描述的主要是smooth插值的妙处。

可以看到,原本是凹凸线,经过线性插值,变成了折线。然后用smooth插值,就变成了平滑曲线。

从插值的角度来说,噪声和随机的区别就是,噪声是连续的,随机是离散的。


float i = floor(x);  // 整数(i 代表 integer)
float f = fract(x);  // 小数(f 代表 fraction)
y = rand(i); //rand()// 就是上面的随机
y = mix(rand(i), rand(i + 1.0), f);
y = mix(rand(i), rand(i + 1.0), smoothstep(0.,1.,f));

image.png

image.png image.png

二维

二维噪声同样要插值,不过下面这种方法 value nosie 和我之前想的略有不同。

因为二维的插值除了要在各自的分量上差值外,还要把x y联系起来,这样整体上看上去就是平滑的。

// value noise 在两个随机数之间插值 
float noise2(vec2 st){ 
    vec2 i = floor(st);
    vec2 f= fract(st);
    	
    // 取周围四格的随机值
    float a = random2(i);
        float b = random2(i + vec2(1.,0.));

        float c = random2(i + vec2(0., 1.));

        float d = random2(i + vec2(1.,1.));

    
    vec2 u = f* f*(3. -2.*f);// 向量乘法还是向量
    u= smoothstep(0.,1. ,f ); // 这个效果和上面的三次多项式差不多,至少肉眼没看出区别
// 差值
return   mix(a,b,u.x) + (c-a) * u.y * (1. - u.x) + (d- b) * u.x * u.y;
}

image.png

最后 细胞噪声

先这样吧。 最后看一个有意思的东西。 这个其实比上面的value noise更好理解。 原翻译是网状噪声,但是动起来之后,感觉更像细胞。

如果我们写一个到某点的距离场函数, 颜色和这个距离关联起来, 结果肯定就是一圈圈的,如果是平滑变化,那就是径向渐变。

在这个基础上,我们增加点的数量,计算当前坐标到每个点的距离, 最后取最近的那个距离,如此一来,围绕每个点都会是径向变化,直到碰到另一个点,两个的点的范围碰撞在一起。

碰撞形成的边界,含义就是到两个点的距离相当,如果是多个区域的交点,那就是到多个点的距离相同。