这个GLSL rand()单线程的起源是什么?

我已经看到这个伪随机数发生器用于在这里和那里提到的着色器周围的networking :

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

它被称为“规范”,或者“我在网上find的一行代码”。

这个function的起源是什么? 这些不变的价值观是否随意,或者是否有一些艺术可供select? 有没有关于这个function的优点的讨论?

编辑:这个function的最古老的引用,我已经遇到这个从2008年2月的档案 ,原来的网页现在正在从网上消失。 但是除此之外,没有更多的讨论。

非常有趣的问题!

我试图找出答案:)首先一个简单的方法来玩它: http : //www.wolframalpha.com/input/? i=plot%28+mod%28+sin%28x* 12.9898 +%2B + Y * 78.233%29 + * + 43758.5453%2C1%29X%3D0..2%2C + Y%3D0..2%29

那么让我们考虑一下我们在这里要做的事情:对于两个input坐标x,y,我们返回一个“随机数”。 现在这不是一个随机数字。 每次我们input相同的x,y都是一样的。 这是一个哈希函数!

函数做的第一件事是从2d到1d。 这本身并不有趣,但是select的数字是不会重复的。 另外我们还有一个浮点加法。 从y或x将会有更多的位,但是这些数字可能只是被选中,所以它会混合。

然后我们抽取一个黑盒子的sin()函数。 这将取决于实施!

最后,通过乘以和取小数来放大sin()实现中的错误。

在一般情况下,我认为这不是一个好的散列函数。 sin()是GPU上的一个黑盒子,用数字表示。 应该可以通过几乎所有的哈希函数来构造一个更好的哈希函数并将其转换。 最难的部分是将用于CPU散列的典型整数操作转换为浮点(一半或32位)或定点操作,但应该是可能的。

同样,这个作为散列函数的真正问题是sin()是一个黑盒子。

起源可能是这样的论文: “随着y = [(a + x)sin(bx)] mod 1”,WJJ Rey,第22届欧洲统计人员会议和第7届维尔纽斯概率论会议数理统计,1998年8月

编辑:因为我找不到本文的一个副本,并且“TestU01”引用可能不清楚,这里是TestU01在伪C中所述的scheme:

 #define A1 ??? #define A2 ??? #define B1 pi*(sqrt(5.0)-1)/2 #define B2 ??? uint32_t n; // position in the stream double next() { double t = fract(A1 * sin(B1*n)); double u = fract((A2+t) * sin(B2*t)); n++; return u; } 

其中唯一推荐的常数值是B1。

请注意,这是一个stream。 转换为1D散列“n”变成整数网格。 所以我的猜测是有人看到这个,并将“t”转换成一个简单函数f(x,y)。 使用上面的原始常量将产生:

 float hash(vec2 co){ float t = 12.9898*co.x + 78.233*co.y; return fract((A2+t) * sin(t)); // any B2 is folded into 't' computation } 

常数值是任意的,特别是它们非常大,并且与素数相距小数点。

高振幅窦的1的模数乘以4000是周期函数。 它就像一个窗帘或一个波纹金属,因为它乘以4000而变得非常小,并且由点积转向一个angular度。

因为函数是二维的,所以点积具有相对于X和Y轴倾斜的周期函数的效果。 大约13/79比例。 这是效率低下,你可以通过做(13x + 79y)的窦实际上达到相同的事情,我也会用较less的math来实现。

如果在X和Y中都find函数的周期,可以对其进行采样,使其看起来像是一个简单的正弦波。

这是放大图的照片

我不知道它的起源,但它与其他许多类似,如果你定期在graphics中使用它,它往往会产生莫尔条纹,你会发现它最终会再次出现。

也许这是一些非经常性的混沌映射,那么它可以解释很多事情,但也可以只是一些大数目的任意操纵。

编辑:基本上,函数fract(sin(x)* 43758.5453)是一个简单的散列函数,sin(x)提供-1到1之间的平滑插值,所以sin(x)* 43758.5453将从 – 43758.5453至43758.5453。 这是一个相当大的范围,所以即使是小的一步x也会提供很大的结果和小数部分的变化。 需要“分数”才能得到范围在-0.99 …至0.999 …之间的值。 现在,当我们有类似哈希函数的东西时,我们应该从vector中为生产哈希创build函数。 最简单的方法是将input向量的任意y分量分别称为“散列”。 但是,那么我们会有一些对称的价值。 因此,我们应该从vector中得到一些值,方法是find一些随机vector,find那个vector的“点”积,这里我们去:fract(sin(dot(co.xy,vec2(12.9898,78.233))) * 43758.5453); 另外,根据所select的vector,在计算“点”积后,其长度应该长时间地具有“正弦”函数的几个间隙。