【问题标题】:Perlin noise different implementationsPerlin 噪声不同的实现
【发布时间】:2020-11-11 06:32:58
【问题描述】:

我已经阅读了一些关于 perlin 噪声的文章,但每个文章似乎都有自己的实现方式:

  1. this 文章中,梯度函数返回单个双精度值。

  2. this 的文章中,梯度被生成为一个 3D 向量。

  3. this 文章中,生成了一个静态的 256 个随机梯度向量数组,并使用置换表挑选了一个随机数组,然后讨论了更复杂的球形梯度细节。

这些只是我看到的一些文章。对于同一算法的所有这些变体,我应该使用哪一种或哪一种适用于什么目的?

我已经使用这些技术中的每一种生成了地形和高度图,它们各自的输出在它们自己的方式上存在很大差异,我无法判断我是否做得对,因为我不知道在输出中寻找什么(因为最后只是随机值)

我只是在寻找有关何时使用什么的上下文,因此任何见解都会非常有用

【问题讨论】:

    标签: math perlin-noise


    【解决方案1】:

    有多种方法可以实现相同的算法,有些比其他更快或更慢,有些更容易或更难理解。 The original implementation by Ken Perlin 光看就很难理解。所以你链接的一些文章(包括我写的#2,耶!),尝试简化实现以使其更容易理解。

    但最终,它的算法完全一样:

    1. 取输入,计算包含输入点的正方形 4 个角的坐标(对于 2D Perlin 噪声,如果使用 3D 版本,则为立方体)
    2. 计算所有 4 个的随机值(首先为每个分配一个随机梯度向量(在 2D 中有 4 种可能性:(+1, +1), (-1, +1), (-1 , -1) 和 (+1, -1)),然后计算这个随机梯度向量与从正方形角到输入点的向量的点积)
    3. 最后,在这 4 个随机值之间进行平滑插值以获得最终值

    在文章 #1 中,grad 函数直接返回点积,而在文章 #2 中,创建向量对象并调用点积函数以明确正在执行的操作(这可能会慢一些与其他实现相比,因为每次您想要运行算法时都会创建和使用大量矢量对象)。

    两种实现是否会生成相同的地形/高度图取决于它们是否为正方形/立方体的每个角生成相同的随机值(点积的结果)。如果两种算法为网格上的每个整数点(所有可能的正方形/立方体的所有角)生成相同的随机值,那么它们将产生相同的结果。 Ken Perlin 的原始实现和 3 篇文章都使用整数数组为每个角(4 种可能的选择)生成一个随机梯度向量来计算点积。所以理论上如果数组是相同的,那么它们应该产生相同的结果。 (除非某些实现使用另一种方法来生成随机向量。)

    我不确定这是否能回答你的问题,所以请不要犹豫,问其他问题:)

    编辑:

    通常,您不会单独使用 Perlin 噪声。因此,对于您想要的每个最终值(例如高度图纹理中的单个像素),您将多次调用噪声函数(八度音阶)。例如:

    float finalValue = 0.0f;
    float amplitude = 1.0f;
    float frequency = 1.0f;
    int octaveCount = 8;
    
    for (int octave = 0; octave < octaveCount; ++octave) {
        finalValue += amplitude * noise(x * frequency, y * frequency, z * frequency);
        amplitude *= 0.5f;
        frequency *= 2.0f;
    }
    
    // Do something fun with 'finalValue'
    

    频率、幅度和八度音阶数是您可以用来产生不同值的最常用参数。

    例如,如果您要生成地形,则需要多个八度音阶。第一个将产生山的粗略形状,因此您需要高振幅(示例代码中为 1.0)和低频(上述代码中也是 1.0)。但是只有这个八度音程会导致非常平滑的地形,没有细节。对于那些小细节,您需要更多的八度音阶,但频率更高(因此在相同的输入范围内(x、y、z),Perlin 噪声值会有更多的起伏),并且更低幅度(你想要一些小细节,因为如果你保持与第一个八度音阶相同的幅度(在示例代码中为 1.0),那么会有很多起伏非常接近并且非常高,这将导致非常崎岖的山(想象一下每走几米就有 100 米 80 度的坡度和斜坡))

    您可以使用这些参数来获得不同的结果。您还可以查找称为“域扭曲”或“扭曲噪声”的东西。基本上,您将噪声函数称为噪声函数的输入。喜欢而不是打电话:

    float result = noise(x, y, z);
    

    你会这样称呼:

    // The numbers used are arbitrary values, you can just play around until you get something cool
    float result = noise(noise(x * 1.7), 0.5 * noise(y * 4.1), noise(z * 2.3));
    

    这可以产生really interesting results

    【讨论】:

    • 使用多层噪声与分形布朗运动分数布朗运动有关。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 2014-02-15
    • 2020-06-06
    • 2020-02-23
    • 2011-09-20
    • 2021-06-30
    • 2013-07-23
    相关资源
    最近更新 更多