柏林噪音不同的实现

Perlin noise different implementations

我看过一些关于 perlin 噪声的文章,但每篇文章似乎都有自己的实现方式:

  1. this文章中,梯度函数returns单双值。

  2. this 文章中,梯度生成为 3D 矢量。

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

这些只是我看到的部分文章。对于同一算法的所有这些变体,我使用哪一个或哪个是 suitable 用于什么目的?

我已经使用这些技术中的每一种生成了地形图和高度图,并且它们各自的输出在他们自己的方式上有很大的不同,我不知道我做的是否正确,因为我不知道要寻找什么输出(因为最后只是随机值)

我只是在寻找一些关于何时使用什么的上下文,所以任何见解都会非常有用

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

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

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

在第 1 篇文章中,grad 函数 returns 直接进行点积,而在第 2 篇文章中,创建了矢量对象并调用了一个点积函数来明确表示正在做什么(这可能会比其他实现慢一点,因为每次要 运行 算法时都会创建和使用大量矢量对象。

2 个实现是否会生成相同的地形/高度图取决于它们是否为 square/cube 的每个角生成相同的随机值(点积的结果)。如果 2 个算法为网格上的每个整数点(所有可能 squares/cubes 的所有角点)生成相同的随机值,那么它们将产生相同的结果。 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 度的落差和斜坡))

您可以使用这些参数来获得不同的结果。还有一种叫做“domain warping”或“warped noise”的东西你可以查一下。基本上,您将噪声函数称为噪声函数的输入。喜欢而不是打电话:

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