C 随机产生的二维噪声
我试图生成一个随机的二维网格,它是从[x,y]坐标按程序生成的(与预先生成二维数字数组相反)。这样做的原因是地图可能很大,而且很有可能实际不需要网格的大部分 以下是我目前掌握的情况:C 随机产生的二维噪声,c,random,procedural-generation,C,Random,Procedural Generation,我试图生成一个随机的二维网格,它是从[x,y]坐标按程序生成的(与预先生成二维数字数组相反)。这样做的原因是地图可能很大,而且很有可能实际不需要网格的大部分 以下是我目前掌握的情况: double value_at(Grid *grid, int seed, int x, int y) { srand(seed + x + y * grid->width); return (double)rand() / (RAND_MAX + 1.0); } 更新:要求处的value_具有参考
double value_at(Grid *grid, int seed, int x, int y) {
srand(seed + x + y * grid->width);
return (double)rand() / (RAND_MAX + 1.0);
}
更新:要求处的value_具有参考透明度(尽可能)。因此,以下观点必须成立:
int i = value_at(grid, seed, 100, 100);
int j = value_at(grid, seed, 100, 100);
assert(i == j);
换句话说,如果我用相同的参数调用value\u at
,那么无论在程序执行期间调用它多少次,它都应该给出相同的结果。
这是因为我试图生成随机地形,这将涉及不同网格点之间的插值;用户也可能会重新访问网格中的某个点
它正确地生成了网格,但是我在输出中看到了很多规律:
您可以看到有一种“颗粒”,它使线在输出中沿对角线移动
我正在做一些研究,但我很难找到这样做的方法。有人知道如何让网格变得更“随机”一点吗
更新:感谢ldgabbay提供的链接,我添加了一个简单的旋转哈希函数,如下所示:
int simple_hash(int * is, int count) {
// this contains a bunch of arbitrarily chosen prime numbers
int i;
unsigned int hash = 80238287;
for (i = 0; i < count; i++){
hash = (hash << 4) ^ (hash >> 28) ^ (is[i] * 5449 % 130651);
}
return hash % 75327403;
}
double value_at(Grid *grid, int seed, int x, int y) {
int is[] = {x, y, seed};
srand(simple_hash(is, 3));
return (double)rand() / (RAND_MAX + 1.0);
}
以下是它生成的一些示例网格:
我认为在使用srand
使值在
处具有确定性方面存在一个微妙的缺陷。通常,一个随机数生成器被播种一次,并且从中产生的数字是伪随机的。但是,在这种方法中,您将看到随机数生成器中为不同种子生成的第一个随机数。这可能不像您希望的那样随机。我认为这在很大程度上取决于系统上随机数生成器的实现
既然你有不能保存随机序列的要求,我有一些想法
(一)
尝试更改用于更改随机种子的公式。现在,当你在网格中移动时,你的种子会发生非常可预测的变化。(例如,seed、seed+1、seed+2、…、seed+width、seed+width+1等)您需要的是:
srand(seed + hash(x + y * grid->width));
其中,hash
是一种简单的方法,它将[0,width*height]中的一个数字映射到该范围内的另一个数字,但不太可预测
可以找到一些简单的散列函数
(二)
在获取随机值之前,从随机数生成器中弹出一个确定数量的随机数。因此,在返回语句之前,添加一行,如:
for (i=0; i!=skip; ++i) rand();
您可以将skip
设置为一个固定的数字,甚至可以将其设置为x、y甚至seed的确定函数。停止对get函数进行种子设定。随机种子,类似于srand((unsigned int)time(NULL));
属于main()的顶部
;一次用于该过程,除非您有意尝试重新生成相同的序列(这里没有出现这种情况)。从这开始。(无关:如果我缓慢滚动页面,图像在测试像素刷新烧坏方面做得非常好=P)。我在问题中添加了一个额外的要求。如果我在过程开始时只播一次种子,则该要求不成立。因此,您想要的是随机的,但只有一次,然后是重复的?在我看来,它似乎知道初始状态,并将图像存储在存储器中以供检索(即使是作为一个双倍的矩阵)可能是实现这一点的机制。或者我仍然不了解真正的问题(最近这不太可能)。如果两次调用value\u at()
给定相同的参数必须生成相同的结果,最好不要使用系统srand()/rand()
因为这些函数对于其余的代码都是无用的。最好使用你自己的robbrit_rand()
。很多互联网源代码都可以用于好的random()函数。而不是srand(seed+hash(x+y*grid->width));
,不会散列(seed+x+y*grid->width))
更有意义吗?是的,也可以这样做。重点是阻止srand
的参数是可预测的。太好了,效果很好!我最后对列表中的旋转散列函数进行了调整,加入了一些额外的大素数,直到我得到了一些看起来非常随机的参数。我将发布c在问题中。