我们前面所讲的函数均为遵守秩序的函数,但我们这节课将给大家讲解随机数。在glsl
中并没有提供生成随机数函数公式,如果需要实现随机数函数利用glsl
现有公式模拟出随机数值。随机数在glsl
中有很多应用像是噪点图就是利用随机数来实现。因此在实现噪点图之前先了解如何生成随机数函数。
一维随机数
我们在前面给大家介绍过fract函数与sin函数,在本节课中我们将利用这两个函数得到随机数字。sin
函数值域范围在[-1,1]
之间,在这个范围内可以将正弦函数值乘以一个比较大的值例如1000,然后使用fract
函数只取小数部分的值,就能模拟打散成伪随机数。最后结果会发现相乘的数值越大sin
函数获取到的结果越离散越没有规律。
float random(float x)
{
float y = fract(sin(x)*100000.0);
return y;
}
我们来看一下这个上述函数图像效果:
由图像可以清晰分辨出,fract(sin(x)*100000.0)
返回的值参差不齐,故而就形成了随机数字。
肯定有同学好奇,为什么sin函数乘那么大的数字,如果不乘又如何:
sin函数乘20.3,这看起来很酷,但是我们明显发现线的密集度不在像*100000.0
那样高了。
根据上述实践我们得到sin函数倍数越大,随机数变化越明显。当我们不断的进行增大时,其实我们增大的是sin函数的幅度,但是由于fract的限制,这其实是增加fract的定义域,它会形成-1——1之间的更加密集的点。我们shader中结果如下图所示:
二维随机函数
了解一维随机函数之后可以将它应用到二维随机上。在glsl
纹理顶点上有x轴和y轴,就需要将二维向量转化成一维浮点数。这里将二维uv
向量使用dot
函数将各分量分别相乘后相加,这里相乘的分量值是vec2(12.9898,78.233)
(若有必要可以修改该向量值)。最后和一维随机函数一样执行sin
函数和fract
函数获取最终伪随机数。
float random (vec2 uv)
{
return fract(sin(dot(uv.xy, vec2(12.9898,78.233))) * 43758.5453123);
}
我们可以加入时间变量,让随机数动态起来
float random (vec2 uv)
{
return fract(sin(dot(uv.xy, vec2(12.9898,78.233)+time)) * 43758.5453123);
}
这个图像像极了我们童年时候的老电视机,没有信号,花屏的时候。你是不是觉得这样就完了,实际上目前的随时数不是真正的随机,他是“伪随机”。比如我们看以下的代码
float random (vec2 uv)
{
return fract(sin(dot(uv.xy, vec2(1.,1.)+time)) * 43758.5453123);
}
由上述代码显示的结果我们可以发现,再等于特定值得时候,返回的结果是固定的,并且random函数返回来的数值过于随意化,而我们在日常中看到的木头斑纹、大理石等等似乎在随意化中又有一种规律性,为了解决此问题,我们引出了下一论题。