OpenGL Shader-随机数生成

2,936 阅读2分钟

「这是我参与2022首次更文挑战的第9天,活动详情查看:2022首次更文挑战

glsl中并没有提供生成随机数函数公式,如果需要实现随机数函数利用glsl现有公式模拟出随机数值。随机数在glsl中有很多应用像是噪点图就是利用随机数来实现。因此在实现噪点图之前先了解如何生成随机数函数。

随机数生成

一维随机函数

可以利用正弦sin函数模拟一维随机数。sin函数值域范围在[-1,1]之间,在这个范围内可以将正弦函数值乘以一个比较大的值例如1000,然后使用fract函数只取小数部分的值,就能模拟打散成伪随机数。最后结果会发现相乘的数值越大sin函数获取到的结果越离散越没有规律。

float random(float x)
{
    float y = fract(sin(x)*100000.0);
    return y;
}
y = fract(sin(x)*1.0)y = fract(sin(x)*100.0)y = fract(sin(x)*1000.0)
image.pngimage.pngimage.png

二维随机函数

了解一维随机函数之后可以将它应用到二维随机上。在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);
}

随机数加强

glsl中通过取巧的方式生成随机数其实是一个伪随机的过程。在实验过程中使用一维随机数生成函数会发现使用sin函数在-1.5707和1.5707上会有较大波动。或许可以通过一些方法让伪随机数更加“伪随机”,例如两个伪随机函数相乘,开平方根等方法。

float y = random(x) * random(x);
float y = sqrt(random(x));
float y = pow(random(x),5.)
// 二维特殊处理方式
fract(52.9829189f
              * frac(uv.x * 0.06711056f
                   + uv.y * 0.00583715f))

总结

glsl上虽然无法做到完全意义上的随机,但已经能够在日常开发应用中起到重要作用。类似开篇说到噪点图确实能够提供方法支持实现,可以使用二维随机函数实现噪点图效果。

image.png

参考