我已经看到了此伪随机数生成器,可用于在网上和此处引用的着色器:
float rand(vec2 co){
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}
它被不同地称为“规范”,或“我在网上某处找到的单线”。
此功能的起源是什么?常数值看起来像是任意的吗,还是选择某些艺术?是否有讨论此功能的优点?
我已经看到了此伪随机数生成器,可用于在网上和此处引用的着色器:
float rand(vec2 co){
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}
它被不同地称为“规范”,或“我在网上某处找到的单线”。
此功能的起源是什么?常数值看起来像是任意的吗,还是选择某些艺术?是否有讨论此功能的优点?
Answers:
非常有趣的问题!
我试图在输入答案时弄清楚这个问题:)首先是一种简单的玩法: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
然后,让我们考虑一下我们要在这里做什么:对于两个输入坐标x,y,我们返回一个“随机数”。现在,这不是一个随机数。每次输入相同的x,y都是相同的。这是一个哈希函数!
函数要做的第一件事是从2d变为1d。这本身并不有趣,但是选择了数字,因此通常不会重复。另外,我们在那里还有一个浮点数。y或x还会有更多的位,但是可能只是正确选择了数字,所以进行了混合。
然后我们对黑盒sin()函数进行采样。这将在很大程度上取决于实施!
最后,它通过乘以小数来放大sin()实现中的错误。
在一般情况下,我认为这不是一个好的哈希函数。sin()在GPU上是一个数字上的黑匣子。通过采用几乎所有哈希函数并将其转换,应该可以构造出更好的代码。困难的部分是将cpu哈希中使用的典型整数运算转换为float(half或32bit)或定点运算,但是应该可行。
同样,将其作为哈希函数的真正问题是sin()是一个黑匣子。
起源可能是论文: “借助y = [(a + x)sin(bx)] mod 1生成随机数”,WJJ Rey,第22届欧洲统计学家会议以及第七届维尔纽斯概率论会议和数理统计,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
}
fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * (co.xy + vec2(43758.5453, SOMENUMBER))
以符合论文所要使用的功能。
a
和b
)的起源的问题仍然存在,但是您引用的论文中可能已经使用过。
常数是任意的,尤其是它们非常大,并且与质数相距小数点后两位。
大于1的高振幅窦的系数乘以4000是周期函数。就像是百叶窗或波纹状金属一样很小,因为它乘以4000,然后由点积成角度旋转。
由于该函数是二维函数,因此点积具有使周期函数相对于X和Y轴倾斜的效果。以约13/79的比例。这是低效的,您实际上可以通过做(13x + 79y)的正弦来实现相同的目标,这也将以较少的数学实现相同的目标。
如果同时在X和Y中找到函数的周期,则可以对其进行采样,以使其再次看起来像一个简单的正弦波。
这是它的图片放大图
我不知道其起源,但它与许多其他起源相似,如果您以固定间隔在图形中使用它,则可能会产生波纹图案,并且您可能会发现它最终再次出现。
(13x + 79y)
,因为dot(XY, AB)
会做你描述什么,因为它的点积,其中x,y dot 13, 79 = (13x + 79y)
也许是一些非周期性的混沌映射,然后它可以解释很多事情,但是也可以只是一些任意的大数操作。
编辑:基本上,函数fract(sin(x)* 43758.5453)是一个简单的类似于哈希的函数,sin(x)提供-1到1之间的平滑sin插值,因此sin(x)* 43758.5453将是从-进行插值43758.5453至43758.5453。这是一个相当大的范围,因此即使x的步长很小,结果也会产生较大的步长,而分数部分的变化确实很大。需要“ fract”才能获得-0.99 ...至0.999 ...范围内的值。现在,当我们有类似哈希函数的东西时,我们应该根据向量创建用于生产哈希的函数。最简单的方法是分别对输入向量的任何y分量x调用“哈希”。但是,那么我们将有一些对称值。因此,我们应该从向量中获取一些值,方法是找到一些随机向量,并找到该向量的“点”乘积,然后开始:fract(sin(dot(co.xy,vec2(12.9898,78.233)))* 43758.5453); 同样,根据选择的向量,在计算“点”积之后,其长度应足够长以具有“正弦”函数的多个垂直点。