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) ;
}
这个函数是伪随机,很明显,只要传参确定返回值就确定。但是规律性一般也看不出来,所以用作随机数够了。
这个函数需要注意的是,系数的小数位是必要的。
二维
二维随机就是一个二元函数。 实现方式,可以直接套用一维随机,也可以用点乘,可以输出单个数,也可以输出二维向量。
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) ;
噪声
噪声和随机有什么区别呢?
区别大概就是,虽然是随机但不是那么的随机。 是不是像极了某某产品的经典需求。
像大海的波涛,沉积岩的纹理,树叶的脉络等等,都充满了随机(不可预测性)。伪随机是可以预测的,我们这里实际上还是伪随机。
但是我们只是想去模拟它。
一般的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));
二维
二维噪声同样要插值,不过下面这种方法 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;
}
最后 细胞噪声
先这样吧。 最后看一个有意思的东西。 这个其实比上面的value noise更好理解。 原翻译是网状噪声,但是动起来之后,感觉更像细胞。
如果我们写一个到某点的距离场函数, 颜色和这个距离关联起来, 结果肯定就是一圈圈的,如果是平滑变化,那就是径向渐变。
在这个基础上,我们增加点的数量,计算当前坐标到每个点的距离, 最后取最近的那个距离,如此一来,围绕每个点都会是径向变化,直到碰到另一个点,两个的点的范围碰撞在一起。
碰撞形成的边界,含义就是到两个点的距离相当,如果是多个区域的交点,那就是到多个点的距离相同。