了解Perlin噪声


31

在与Diamond Square合作后,我正在玩Perlin Noise。我遵循了Hugo Elias实现,实现基本上是用x,y作为输入来生成一系列函数以抛出每个坐标值。

我的PHP代码在这里

我有两个问题:

如何使用该算法在数组中生成高度图?我并没有完全理解它,只是将伪代码移植到PHP,但是在读取算法“神奇地”为给定的每个x,y点(显然,不必读取其)的转换值后,执行了最后一个函数(map_perlined)相邻的值),当用作随机函数时,我得到这个mt_rand(-100,100)/100;

enter image description here

这在使用密码时:(1.0-(($n*($n*$n*15731+789221)+1376312589)&0x7fffffff)/1073741824.0;顺便说一句,可以在PHP中“按原样”实现吗?):

enter image description here

因此,总结三个问题:

  1. 我的代码正确吗?
  2. 可以按代码中所述将random函数移植到PHP吗?它不会抛出任何错误,但是结果不存在。
  3. 我实际上如何使用该算法?

更新

好的,为Gustavson论文中显示的代码添加了一个PHP端口,正如其他编码人员所说,它仅生成一个八度。是否还有其他有用的站点/论文/指南,说明如何结合使用多个八度音阶,幅度,频率等来控制噪声功能?在Gustavson的论文中仅显示了结果,而不是算法的实际实现,也许我遗漏了一些东西?

更新2
@NATHAN

我做了类似的事情:

$persistence = 0.5;

for ($j = 0; $j < $size; $j++) {
    for ($i = 0; $i < $size; $i++) {

        for ($o = 0; $o < 8; $o++) {
            $frequency = pow(2,$o);
            $amplitude = pow($persistence, $o);
            $value += SimplexNoise($i*$frequency, $j * $frequency) * $amplitude;
            }

            //$value = SimplexNoise($i, $j) + 0.5 * SimplexNoise($i, $j) + 0.25 * SimplexNoise($i, $j);
            $this->mapArray[$i][$j] = new Cell($value);

在将值归一化为0..1之后,我得到了一个相当沉闷的高度图,例如:

enter image description here

我如何播种地图?也许我需要实现的是带有第三个值的3d版本随机高度?但是,如果是这样,我必须找出考虑邻居值的方法,而这些值将以菱形平方算法结尾,而这正是我不想做的。

更新3

更多Perlin工作。我还没有找到一种方法可以将噪声引导到我的结果中。检查以下八度和最终结果:

八度I至IV

Octave1Octave2Octave3Octave4

总结

Octaves 1-4 summed

每个八度几乎相同。检查代码:

$persistence = 0.5;

    for ($j = 0; $j < $size; $j++) {
      for ($i = 0; $i < $size; $i++) {
        $value = 0;

        for ($o = 0; $o < 4; $o++) {
          $frequency = pow(2,$o);
          $amplitude = pow($persistence, $o);
          $value += improved_noise($i*$frequency, $j*$frequency, 0.5)*$amplitude;

        }
        $this->map[$i][$j] = new Cell($value);

结果归一化。您将使用什么对噪声的产生产生重大影响?我看到了一些例子,其中改变幅度会产生柔软或粗糙的表面,但是即使幅度很大,差异也很小。


只需将多个实例加在一起,就可以增加频率并降低幅度,例如:perlin(x)+ 0.5 * perlin(2 * x)+ 0.25 * perlin(4 * x)+ ...(多达你要)。您也可以尝试更改因素以获得不同的外观。他们并不需要为2的权力
弥敦道里德

1
更新后,看来您没有正确缩放Y-我太累了,无法使用PHP(因为我不了解PHP);但是当我第一次实施perlin时,我的母语也遇到了类似的问题。也可以杀死八度音,只调试一级Perlin。
乔纳森·迪金森

有人要更新我的III吗?
加百利·A·佐里拉

Answers:


28

您实现的不是Perlin噪音。我不确定为什么雨果·埃里亚斯(Hugo Elias)这么说,但是他很困惑。 是Ken Perlin的参考实现。它实际上并没有调用任何外部随机数生成器,而是使用内置的哈希函数来生成伪随机梯度向量。

还请注意,Perlin噪声仅包含一个八度。正如Hugo Elias所建议的那样,将多个八度音(噪声函数的缩放实例)加起来是一种有用的技术,但不是Perlin噪声的一部分。通过这种操作得到的结果称为分形噪声,有时也称为“分形布朗噪声”(由于假定类似于布朗运动)。

如果您想从几何上了解算法的作用,请尝试本文。它涉及另一种称为“简单噪声”的噪声,但也包括对经典Perlin噪声的解释。顺便说一句,Perlin也发明了单形噪波,它应该是对他的经典噪波的改进,因此,如果您对玩噪波功能感兴趣,也可以尝试实现它。


2
+1为古斯塔夫森的论文。到目前为止,我以最清晰的方式解释了Perlin和单纯形噪声。显然是单纯形噪声规则!
FxIII

不久前我也找到了那篇论文,但雨果的看上去更简单。我将阅读并尝试一下!谢谢!
加百利·佐里拉

2
下载单纯噪声时要小心,它可能有病毒;)
bobobobo

我知道这是一个古老的话题,但是说参考实现不使用随机数是不正确的。初始化库时(或第一次调用噪声函数),将生成256个随机梯度。您引用的哈希只是将无穷整数集强制为已缓存的[0,255]范围。从本质上讲,这只是一个查询表的优化,例如,如果您使用网格坐标为PRNG播种并使用它生成梯度,则该算法的效果就好得多。
bcrist 2014年

@bcrist我认为您指的是Perlin噪声的旧版本。我链接到的 Perlin的“改进的噪声” 使用一组固定的12个梯度矢量,而不是256个随机矢量。它使用置换表作为哈希函数将网格坐标映射到这12个梯度向量之一。
内森·里德

11

这是一个普遍的误解。雨果·埃里亚斯(Hugo Elias)所说的“佩林”噪声实际上是分形的或粉红色的噪声。为了更好地了解Perlin噪声是什么,您可以阅读内森·里德(Nathan Reed)的答案中链接的Perlin文章或libnoise文档(那里存在相同的错误:Perlin噪声是他们所谓的梯度噪声)或CoherentNoise文档

现在,要实际回答您的问题:由于噪声频率太高,您没有得到预期的结果。您的频率从1开始并增加,这意味着结果贴图中的每个像素都有一个随机值。要查看更精细的地图结构,您需要“放大”噪声。我不是真的说PHP,但是我想代码应该像这样:

$arrayMap[$i][$j] = PerlinNoise_2D($i/$width, $j/$height, $p, $octaves);

也就是说,您在整个地图上“伸展”了一段噪声。当然,您可以使用其他系数-只需尝试不同的系数,看看会发生什么。


感谢连贯的噪声文档!我看到您已经编写了它:) libnoise文档中有什么错误?佩林噪声不是梯度噪声吗?
legends2k
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.