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

时间:2017-08-11 00:09:38

标签: algorithm computer-vision perlin-noise

我通过this explanation of Perlin noise阅读,它描述了一个哈希函数,它计算所有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 个答案:

答案 0 :(得分:2)

Perlin噪声生成背后的关键思想是创建一个点网格,每个点都分配一些矢量值,然后以特定方式在这些点之间进行插值。

我检查了Ken Perlin's original paper on Perlin noise,它似乎早在原始论文中他建议使用哈希函数来执行此操作:

  

将整数点阵中的每个点与伪随机值和x,y和z梯度值相关联。更准确地说,将三个整数的每个有序序列映射成四个实数[a,b,c,d] = H([x,y,z])的不相关有序序列,其中[a,b,e,d]在[x,y,z]处定义具有梯度[a,b,c]和值d的线性方程。 H最好实现为哈希函数。

(强调我的)。

我怀疑其原因与内存问题有关。 Perlin噪声生成要求在算法运行过程中多次重新评估空间中不同点的梯度函数。因此,你可以

  1. 有一些公式,给定空间中的一个点,计算渐变,或
  2. 显式创建表并存储您需要的所有随机值。
  3. 选项(1)是Ken Perlin提出的建议。这种方法的优点是存储梯度所需的内存使用量是最小的;你只需要使用哈希函数。

    选项(2)是你提出的。这很好用,但它使用了大量的内存(你需要为你正在使用的整数点阵中的每个点存储多个值)。请记住,Perlin的论文是在1985年(!)写回来的,当时的记忆比现在要多得多。

    我怀疑你可以使用任何一种方法,但鉴于你不需要真正的随机性,良好的哈希函数所提供的伪随机性就足够了。

    我无法解释为什么你读过的那篇文章的作者选择使用他们所做的特定哈希函数。我的猜测是它“足够随机”且足够快,以至于它不会成为计算中的瓶颈;请记住,哈希函数在噪声生成代码中被调用了很多次。这似乎是实施Perlin噪声的标准方法;甚至是Ken Perlin mentions using this hash function on his site

    无法做的是您提出的仅让变量aaaaababa等等的方法。顺便说一下,变量的可怕的名称!)是随机的。原因是Perlin噪声算法要求您多次重新评估给定点的噪声项,并期望它每次都会返回相同的值。如果你想计算真正的随机值,你可以这样做,但是你需要缓存你的结果,这样你就可以在每个点给出一致的噪声项答案。