为什么Perlin噪声使用哈希函数而不是计算随机值?

3
我正在阅读这篇解释Perlin噪声的文章,它描述了一个哈希函数,用于计算所有x、y坐标的随机点。如果x、y坐标哈希是随机生成的,最终用于计算梯度等,为什么我不能随时生成随机数?我们使用哈希图的排列来查找我们的随机值,只是优化的问题吗?我能想到的唯一原因是通过哈希图的排列会产生平滑效果,但我不知道如何理解。为澄清起见,我指的是代码中的这部分内容:
private static readonly int[] p = { 151,160,137,91,90,15,                 // Hash lookup table as defined by Ken Perlin.  This is a randomly
    131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,    // arranged array of all numbers from 0-255 inclusive.
    190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
    88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
    77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
    102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
    135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
    5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
    223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
    129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
    251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
    49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
    138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
};

int aaa, aba, aab, abb, baa, bba, bab, bbb;
        aaa = p[p[p[    xi ]+    yi ]+    zi ];
        aba = p[p[p[    xi ]+inc(yi)]+    zi ];
        aab = p[p[p[    xi ]+    yi ]+inc(zi)];
        abb = p[p[p[    xi ]+inc(yi)]+inc(zi)];
        baa = p[p[p[inc(xi)]+    yi ]+    zi ];
        bba = p[p[p[inc(xi)]+inc(yi)]+    zi ];
        bab = p[p[p[inc(xi)]+    yi ]+inc(zi)];
        bbb = p[p[p[inc(xi)]+inc(yi)]+inc(zi)];

为什么我们不直接按照以下方式初始化数值?
aaa = random(255)
aab = random(255)
// ...
1个回答

7
Perlin 噪声生成背后的关键思想是创建一个点网格,每个点都被赋予某些向量值,然后以特定方式在这些点之间进行插值。
我查看了 Ken Perlin 关于 Perlin 噪声的原始论文,似乎早在最初的论文中他就推荐使用哈希函数来实现这一点:
为整数格子中的每个点关联一个伪随机值和 x、y 和 z 梯度值。更准确地说,将每个有序的三元组映射到四个无关的实数序列 [a,b,c,d] = H([x,y,z]) 中,其中 [a,b,e,d] 定义了梯度 [a,b,c] 和值 d 在 [x,y,z] 处的线性方程。H 最好作为哈希函数实现。(强调为本人添加)
我怀疑这样做的原因与内存问题有关。Perlin 噪声的生成需要在算法运行期间多次重新评估空间中不同点的梯度函数。因此,您可以选择:
1. 有一些公式,给定空间中的一个点,即可计算出其梯度;或者 2. 显式地创建表格并存储所有所需的随机值。
肯·珀林提出了第一种方法。这种方法的优点是所需的存储梯度的内存使用量最小;您只需要使用哈希函数即可。
第二种方法是您提出的。这样做完全没有问题,但它会使用大量的内存(您需要为要处理的整数格子中的每个点存储多个值)。请记住,珀林的论文是在 1985 年(!)撰写的,当时内存比今天稀缺得多得多。
我的猜测是,您可以使用任何一种方法,但鉴于您不需要真正的随机性,良好的哈希函数所提供的伪随机性应该足够了。
我无法解释为什么您读的那篇文章的作者选择使用特定的哈希函数。我的猜测是,它“足够随机”且足够快,以至于它不会成为计算中的瓶颈;请记住,在噪声生成代码中会多次调用哈希函数。这似乎是实现 Perlin 噪声的标准方法;甚至肯·珀林也在他的网站上提到了使用这种哈希函数。
您提出的方法是让变量aaa,aab,aba等随机,这种方法是不可行的。原因在于Perlin噪声算法需要在给定点重新评估噪声项多次,并期望每次都会返回相同的值。如果您想计算真正的随机值,可以这样做,但是您需要缓存结果,以便在每个点上都返回一致的噪声项答案。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接