什么';这个GLSL rand()一行的来源是什么?

什么';这个GLSL rand()一行的来源是什么?,glsl,shader,prng,Glsl,Shader,Prng,我已经看到了在着色器中使用的伪随机数生成器: 它被各种各样地称为“canonical”,或者“我在网上某处找到的一行” 这个函数的起源是什么?常量值是否像它们看起来那样随意,或者它们的选择是否有艺术性?有没有讨论过这个功能的优点 编辑:我遇到的关于这个函数的最古老的引用是,原来的页面现在已经从web上消失了。但是在那里没有比其他地方更多的关于它的讨论。非常有趣的问题 我试图在键入答案时找出答案:) 首先是一种简单的玩法: 然后让我们想想我们在这里要做什么:对于两个输入坐标x,y,我们返回一个“随

我已经看到了在着色器中使用的伪随机数生成器:

它被各种各样地称为“canonical”,或者“我在网上某处找到的一行”

这个函数的起源是什么?常量值是否像它们看起来那样随意,或者它们的选择是否有艺术性?有没有讨论过这个功能的优点


编辑:我遇到的关于这个函数的最古老的引用是,原来的页面现在已经从web上消失了。但是在那里没有比其他地方更多的关于它的讨论。

非常有趣的问题

我试图在键入答案时找出答案:) 首先是一种简单的玩法:

然后让我们想想我们在这里要做什么:对于两个输入坐标x,y,我们返回一个“随机数”。这不是一个随机数。每次我们输入相同的x,y都是一样的。这是一个散列函数

函数要做的第一件事是从2d转到1d。这本身并不有趣,但选择的数字不会重复。我们还有一个浮点加法。y或x中还会有一些位,但数字可能选择正确,因此它会进行混合

然后我们对一个黑盒sin()函数进行采样。这在很大程度上取决于实施情况

最后,它通过乘以并取分数来放大sin()实现中的错误

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


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

常量值是任意的,特别是它们非常大,并且距离素数只有几位小数

高振幅正弦的模量大于1乘以4000是一个周期函数。它就像一个百叶窗或者一个波纹金属,因为它被乘以4000,然后以点积的角度旋转

由于函数是二维的,所以点积具有在相对于X轴和Y轴的倾斜方向上转动周期函数的效果。比例大约为13/79。这是低效的,你实际上可以通过做(13x+79y)的正弦来达到同样的效果。这也可以用更少的数学来达到同样的效果

如果你发现函数的周期在X和Y两个方向,你可以对它进行采样,使它看起来像一个简单的正弦波

这是一张放大的照片


我不知道它的起源,但它与许多其他的类似,如果你在图形中以固定的间隔使用它,它会产生莫尔图案,你可以看到它最终会再次出现。

也许它是一些非循环混沌映射,那么它可以解释很多事情,但也可能只是一些任意操纵的大数字

编辑:基本上,函数fract(sin(x)*43758.5453)是一个简单的散列函数,sin(x)提供了-1到1之间的平滑sin插值,因此sin(x)*43758.5453将是从-43758.5453到43758.5453的插值。这是一个相当大的范围,所以即使x中的小步进也会提供大的步进结果,并且在分数部分会有很大的变化。需要“分形”来获得-0.99范围内的值。。。至0.999。 现在,当我们有类似于散列函数的东西时,我们应该从向量中创建用于产生散列的函数。最简单的方法是分别调用输入向量的x或y分量的“散列”。但是,我们会有一些对称的值。所以,我们应该从向量中得到一些值,方法是找到一些随机向量,然后找到向量的“点”积,这里是:fract(sin(dot(co.xy,vec2(12.9898,78.233))*43758.5453);
此外,根据选择的向量,其长度应该很长,直到在计算“点”积之后有几个“sin”函数的周期。

来源可能是论文:“关于生成随机数,借助y=[(a+x)sin(bx)]mod 1”,W.J.J.Rey,第22届欧洲统计学家会议和第7届维尔纽斯概率论和数理统计会议,1998年8月

编辑:由于我找不到这篇文章的副本,而且“TestU01”参考可能不清楚,下面是伪C中TestU01中描述的方案:

#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

请注意,这是针对流的。转换为一维散列“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
}

我不相信这是真正的起源,但OP的代码在帕特里西奥·冈萨雷斯·维沃(Patricio Gonzalez Vivo)和詹·洛(Jen Lowe)的《着色器之书》(the Book of Shaders)中作为代码示例呈现。在他们的代码中,Patricio Gonzales Vivo被引用为作者,即“//author@patriciogv-2015”


由于OP的研究可以追溯到更久远的年代(08年),该来源至少可以解释它的受欢迎程度,作者或许可以对其来源有所了解。

但在GPU上,X和Y的范围为0..1,如果更改图形,这看起来更随机。我知道这听起来像是一个陈述,但实际上这是一个问题,因为我的数学教育在18岁结束。我知道,我只是放大了,这样你就可以看到随机函数是那种形式的,除了脊线变化非常快,除了你必须放大很小才能看到变化。。。你可以想象,在山脊上取点会得到非常随机的数字,从0到1的高度,1到1的x和y值。哦,我理解,这对于任何一个随机数生成来说都是非常合理的,它的核心是使用sin函数,它是一个li
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
}